# Playable Ads

本项目是一个基于 Vue3 + TypeScript + Vite 的项目，核心是基于webgl的web端填色，用于创建可播放的广告。

## 背景

我们有一个填色应用app，已经上架到google play 和 app store。 但是投放的广告基本上是静态图片或视频， 没有playable的广告， 本项目立足制作playable的广告， 用于提升广告的互动性和效果。

playable广告的核心是H5页面， 本工程已经实现了基于webgl的web端填色核心玩法，现在需要进一步完善制作成可播放的广告。

## 竞品分析

以下是几家竞品的playbale 广告， 可以作为分析参考， 尤其是页面的规范方面。

### Paint by Number:

1.

```
https://creative-ag-global.umcdn.cn/html/14/df/cf/14dfcf467412065a43ec4d2f1ad63971.html
```

主要展示了一屏十几个填色作品的填列表页，所谓互动的部分其实就是可以滑动该列表页，点击某个列表页进入一个详情页，这属于简单的内容互动展示，没有涉及游戏核心玩法

2.

```
https://creative-ag-global.umcdn.cn/html/df/3a/14/df3a14870fcb67b02292a0eac34c5ab1.html
```

可以滑动选择几个有吸引力的上色作品，点击进入填色详情页， 但同样不能进行填色操作，没有涉及游戏核心玩法，本质还是简单的内容互动展示

### Happy Color

1.

```
https://creative-ag-global.umcdn.cn/html/83/d5/81/83d5810d37e36b92ee5d90517e31b0f9.html
```

页面动效较好， 但也属于内容展示，没有体现核心玩法， 能够互动的部分就是一个手指指向的 PLAY NOW 按钮，点击即进入安装弹框

2.

```
https://creative-ag-global.umcdn.cn/html/85/8a/03/858a031936edfda1009dd6acb5c3ec2f.html
```

这个有涉及一点核心玩法，有提示手型，可点击上色。

### Color asis

```
https://creative-ag-global.umcdn.cn/html/09/2d/44/092d441b80639f462fa667bb3f8964bf.html
```

这个有涉及核心玩法， 可点击上色，结束后撒花动画，展示典型内容，显示“Over 10,000+ pictures”， 可以作为重点对标研究对象

## playable广告规范

各家广告平台对于playable的广告规范如下， 需要仔细研读理解，我们最终发布的内容要符合所有平台的规范：

1. mintergal

```
https://www.playturbo.com/review/doc
```

2. applovin

```
https://p.applov.in/playablePreview?create=1
```

3. unity

```
https://docs.unity.com/zh-cn/grow/acquire/creatives/playable/specifications
```

4. google admod

```
https://support.google.com/google-ads/answer/9981650?hl=en#_HTML
```

gemini关于playable广告的讲解：

```
https://gemini.google.com/share/8340c20dd2d1
```

## 项目目标

制作符合各广告平台的playable ads， 当前可聚焦核心填色玩法的模版， 未来可以可能开发更多模版。

## 技术栈

| 层级         | 技术                                                |
| ------------ | --------------------------------------------------- |
| 渲染引擎     | WebGL 2（自研，无外部 GL 框架）                     |
| 构建工具     | Vite 5 + TypeScript 5                               |
| 打包插件     | vite-plugin-singlefile（输出单文件 HTML）           |
| 广告生命周期 | MRAID 2.0 + Unity DAPI                              |
| 跳转优先级   | `mraid.open()` → `ExitApi.exit()` → `window.open()` |

## 项目结构

```
src/
  filler/         # 广告主逻辑
    index.ts      # 入口，整合加载/CTA/平台初始化
    cta.ts        # CTA 按钮点击 + 高亮动画
    mraid.ts      # 平台生命周期适配（MRAID / Unity DAPI）
    FillerScene.ts# WebGL 填色场景
    FingerHint.ts # 指引手指 DOM overlay
    Loader.ts     # 资源加载
  base/           # 自研 WebGL 2 渲染层
assets/
  res/            # 填色资源包（config.json + 图片）
  css/            # 样式
dist/
  index.html      # 最终产物，单文件自包含 HTML（~985 KB）
```

## 开发调试

### 安装依赖

```bash
npm install
```

### 启动本地开发服务器

```bash
npm run dev
```

### 映射端口到云服务器

```bash
ssh -R 0.0.0.0:5173:localhost:5173 ecs
```

然后可以在浏览器打开：

```
http://42.193.231.145:5173
```

## 构建

```bash
npm run build
```

输出文件：`dist/index.html`（单文件，所有 JS/CSS/图片/字体均内联）

| 指标         | 数值                 |
| ------------ | -------------------- |
| 文件大小     | ~985 KB              |
| Gzip 大小    | ~641 KB              |
| 平台大小限制 | 5 MB（各平台均满足） |

> **注意**：构建前请确认 `src/filler/cta.ts` 中的 `STORE_URL_IOS` / `STORE_URL_ANDROID`：
>
> - **测试阶段**：使用 PBN 落地页（当前默认），避免产生无效转化
> - **正式上线**：换回自己 app 的 Store 链接（文件内有注释说明）

## 多平台测试

### 测试前准备

1. 执行 `npm run build`，确认 `dist/index.html` 为最新产物
2. 检查 `cta.ts` 中的落地页 URL 符合当前测试目的

### Applovin

**预览工具**：https://p.applov.in/playablePreview?create=1

1. 打开预览工具，上传 `dist/index.html`
2. 检查项：
   - [ ] 广告正常加载，WebGL 填色可交互
   - [ ] CTA 按钮可点击（Applovin 通过 `ExitApi.exit()` 关闭广告，落地页由平台后台配置）
   - [ ] 手指引导动画正常显示
   - [ ] 完成填色后撒花 + 结算屏正常展示

### Unity Ads

**规范文档**：https://docs.unity.com/zh-cn/grow/acquire/creatives/playable/specifications

1. 在 Unity Creative 后台上传 `dist/index.html`
2. 检查项：
   - [ ] `dapi.gameReady()` 被正确调用（可在控制台确认）
   - [ ] CTA 跳转正常（Unity 使用 MRAID `mraid.open(url)` 跳转）
   - [ ] 广告尺寸符合规范（单文件 HTML，无外部请求）

### Google AdMob / Google Ads

**规范文档**：https://support.google.com/google-ads/answer/9981650?hl=en#_HTML

1. 使用 Google Web Designer 或 HTML5 验证工具检验
2. 检查项：
   - [ ] 无外部网络请求（所有资源均已内联）
   - [ ] 文件大小满足限制（≤5 MB）
   - [ ] CTA 可正常触发 `window.open(url)`
   - [ ] 不依赖 `document.write` 或被禁用 API

### Mintergal / Playturbo

**规范文档**：https://www.playturbo.com/review/doc

1. 按平台文档要求上传或提交审核
2. 检查项：
   - [ ] MRAID 初始化流程正常
   - [ ] 音频在用户首次交互后解锁（iOS 限制）
   - [ ] CTA 跳转正常

### 真机测试

在真实设备上直接用浏览器打开 `dist/index.html`（可通过云服务器地址访问）：

```
http://42.193.231.145:5173   # dev 模式
# 或将 dist/index.html 放到静态服务器后访问
```

| 设备    | 浏览器  | 检查项                                         |
| ------- | ------- | ---------------------------------------------- |
| iOS     | Safari  | 音频首次交互解锁、手势填色、CTA 跳转 App Store |
| Android | Chrome  | 音频、手势、CTA 跳转 Google Play               |
| Android | WebView | 广告平台内嵌 WebView 行为是否一致              |

## 常见问题

**Q: 填色区域点击没反应？**
A: 检查 WebGL context 是否初始化成功，Console 有无报错。

**Q: 音效不播放（iOS）？**
A: iOS 要求用户交互后才能播放音频，代码已有 unlock 逻辑，确认首次点击后音效正常即可。

**Q: CTA 点击没有跳转？**
A: 各平台跳转机制不同——Applovin 由平台后台控制落地页；MRAID 环境下用 `mraid.open(url)`；其余环境用 `window.open(url)`。

**Q: 构建产物超过平台大小限制？**
A: 检查 `assets/res/` 下的图片资源，压缩大尺寸图片后重新构建。
