The Multi-Platform Nightmare

A single playable ad needs to run on Facebook, TikTok (Pangle), Google Ads, and often a custom landing page. Each platform has its own MRAID specification, its own event API, and its own file format requirements. Facebook expects a single HTML file with FbPlayableAd.js. TikTok expects a ZIP with an index.html entry point. Google expects MRAID 2.0 compliance.

Building one creative that works everywhere is hard enough. Building 50 variants — each with different CTAs, color schemes, and game mechanics — without a dedicated engineering team per platform is where most playable ad programs stall.

PlayableAd Studio solves this with a build pipeline that takes a single Cocos Creator project and automatically generates platform-specific builds. This post breaks down the pipeline architecture, the template system, and the cloud infrastructure that makes it possible.

Pipeline Architecture

```

[Cocos Creator Project (.ccreator)]

Template Parameters (JSON config)

gulp build task

Platform Adapter Layer

├── Facebook Adapter → FbPlayableAd wrapper

├── TikTok Adapter → ZIP + Pangle APIs

└── MRAID Adapter → MRAID 2.0/3.0 + Generic

Minification (html-minifier, uglify-js)

Output verified by platform SDK

Upload to R2 + Shortlink

```

The Template Engine

At the heart of the pipeline is a JSON-based template parameter system. Instead of editing Cocos Creator scenes for each variant, the pipeline takes a config file:

```json

{

"variant_id": "v3",

"cta": {

"text": "Play Now",

"color": "#FF6B35",

"delay_ms": 3000,

"position": "bottom-center"

},

"game": {

"difficulty": 1.5,

"time_limit": 30,

"level_count": 3

},

"branding": {

"logo_url": "https://cdn.example.com/logo.png",

"accent_color": "#FF6B35"

}

}

```

The build pipeline reads these parameters and injects them into the Cocos Creator build output by patching the generated `settings.js` and `project.js` files. This is done via a Node.js script that runs after `gulp build`:

```javascript

// Template injection (simplified)

function injectTemplate(buildDir, params) {

const settingsPath = path.join(buildDir, 'src', 'settings.js');

let settings = fs.readFileSync(settingsPath, 'utf8');

// Inject template params as global config

const injection = `window.__PAS_CONFIG = ${JSON.stringify(params)};`;

settings = injection + settings;

// Apply CTA color to game config

const colorRe = /ctaColor:\\s*['\"][^'\"]*['\"]/;

settings = settings.replace(colorRe, `ctaColor: '${params.cta.color}'`);

fs.writeFileSync(settingsPath, settings);

}

```

Platform Adapters

Each platform adapter is a standalone Node.js module that takes the base Cocos Creator build and wraps it in the platform's required format:

| Platform | Format | SDK | Adapter Size |

|----------|--------|-----|-------------|

| Facebook | Single HTML | FbPlayableAd.js | +2KB |

| TikTok | ZIP archive | Pangle API | +3KB |

| Google Ads | MRAID HTML | MRAID 2.0 polyfill | +1KB |

| Generic | Standalone HTML | None | 0KB |

The adapters share a common MRAID compatibility layer. Each implements the same interface — `initAd()`, `startGame()`, `showCTA()`, `closeAd()` — but maps them to platform-specific APIs under the hood.

The Facebook Adapter in Detail

The Facebook adapter is the most popular, so it's the most optimized. It:

1. Takes the minified Cocos Creator HTML build

2. Injects Facebook's MRAID polyfill (`FbPlayableAd.js`)

3. Wraps game completion detection in `FbPlayableAd.onComplete()`

4. Wraps CTA clicks in `FbPlayableAd.onCTAClick()`

5. Adds Facebook's `fbq` tracking pixel

6. Validates output against Facebook's SDK validator

```javascript

// Facebook adapter core

function buildFacebook(buildDir, params) {

const baseHtml = fs.readFileSync(path.join(buildDir, 'index.html'), 'utf8');

const facebookWrapper = `

<script>

// FbPlayableAd integration

window.FbPlayableAd = window.FbPlayableAd || {};

function onGameComplete() {

if (window.FbPlayableAd.onComplete) {

window.FbPlayableAd.onComplete();

}

}

function onCTA() {

if (window.FbPlayableAd.onCTAClick) {

window.FbPlayableAd.onCTAClick();

}

window.open('${params.cta.url}', '_blank');

}

</script>

`;

// Inject before closing </body>

const output = baseHtml.replace('</body>', facebookWrapper + '</body>');

return output;

}

```

Cloud Infrastructure

The pipeline runs on GitHub Actions with Workers integration. When a new variant is requested:

1. **GitHub Action** clones the Cocos Creator project, runs build + template injection + platform adapters

2. **Workers API** receives the build artifacts and stores them in R2 (`pas-builds/<campaign_id>/<variant_id>/<platform>/index.html`)

3. **Shortlink Worker** generates a unique URL per build (`https://pas.ai-kit.net/c/abc123/v3/fb`)

4. **Status Worker** provides a dashboard showing build history, variant scores, and deployment status

The entire pipeline, from template config to deployed build, takes under 60 seconds for a single variant.

Why This Matters for Marketing Teams

For a marketing team managing multiple ad campaigns, the bottleneck isn't creative ideas — it's engineering bandwidth. Each new variant means a developer writing Cocos Creator code, running builds, and exporting platform-specific files.

PlayableAd Studio's pipeline reduces that to: a marketer edits a JSON config → bot builds and deploys → ad goes live. The developer writes the template once; the marketer generates 50 variants from it.

This is the Hybrid Dev+Marketing philosophy in action: build tools that let non-developers execute technical workflows without breaking the abstraction. The marketer doesn't need to know what MRAID stands for. They just need to know that changing the CTA color to #FF6B35 improved click-through rates.

Next Steps

PlayableAd Studio's build pipeline is Apache 2.0 licensed and available on GitHub. The template parameter system is extensible — add your own config keys and injection rules via a plugin API.

For teams running Cocos Creator 2.4.x playable ads, this pipeline cuts per-variant production time from 30 minutes of developer work to 30 seconds of automated processing. That's the difference between testing 3 variants per campaign and testing 30.