This is a playable ad template built with PixiJS 8 and TypeScript. Use this as a starting point for creating playable ads for various ad networks.
IMPORTANT: Before starting, configure build.json with your app details:
{
"filename": "{app}_{name}_{version}_{language}_{network}",
"app": "YOUR_APP_CODE",
"name": "YourAppName",
"version": "0s",
"language": "en",
"google_play_url": "https://play.google.com/store/apps/details?id=com.your.app",
"app_store_url": "https://apps.apple.com/app/your-app/id123456789"
}| Field | Description | Example |
|---|---|---|
app |
Short app code (2-4 chars) | "MG" for MyGame |
name |
App name for filename | "MyGame" |
version |
Version identifier | "0s", "v1", "test" |
language |
Language code | "en", "ja", "ko" |
google_play_url |
Google Play Store URL | Full URL to your app |
app_store_url |
Apple App Store URL | Full URL to your app |
Store URLs are required! These are used for CTA (Call to Action) redirects when user clicks "Download" or completes the playable.
Output filename example: MG_MyGame_v1_en_applovin.html
# Install dependencies
npm install
# Development server
npm run dev
# Build for preview
npm run build
# Build for specific network
npx playable-scripts build applovin| Network | Command | Output |
|---|---|---|
| Preview | npm run build |
.html |
| AppLovin | npx playable-scripts build applovin |
.html |
| IronSource | npx playable-scripts build ironsource |
.html |
npx playable-scripts build facebook |
.html |
|
| Mintegral | npx playable-scripts build mintegral |
.zip |
| Moloco | npx playable-scripts build moloco |
.html |
| Unity | npx playable-scripts build unity |
.html |
npx playable-scripts build google |
.zip |
Output goes to dist/ folder.
CRITICAL: Maximum 5MB for most ad networks!
See docs/ART_OPTIMIZATION.md for optimization techniques.
| Document | Description |
|---|---|
docs/ADAPTIVE_LAYOUT_SYSTEM.md |
Adaptive positioning system - screen anchors, percentage-based offsets, camera attachment |
docs/BUILD.md |
Build commands and SDK integration |
docs/ART_OPTIMIZATION.md |
Image/audio/Spine optimization |
docs/ADAPTIVE_TESTING.md |
Portrait/landscape adaptation, device testing |
docs/SPINE_WORKFLOW.md |
Spine animation integration (MUST use .skel binary!) |
src/
├── index.ts # Entry point, SDK initialization
├── Game_new.ts # Main game controller, scaling system
├── scenes/
│ ├── PreloadScene.ts # Loading screen with progress bar
│ └── MainScene.ts # Main gameplay scene (customize this)
├── helpers/
│ ├── Adaptive/ # Adaptive positioning system (RECOMMENDED)
│ │ ├── AdaptiveSprite.ts # Sprite with screen anchors
│ │ ├── AdaptiveGroup.ts # Container with relative children
│ │ ├── AdaptiveText.ts # Text with adaptive sizing
│ │ └── constants.ts # Screen anchors, calculations
│ ├── Scale/ # Legacy scaling helpers
│ │ ├── ScaledSprite.ts
│ │ ├── ScaledContainer.ts
│ │ ├── ScaledText.ts
│ │ └── ScaledSpine.ts
│ ├── AssetsInlineHelper.ts # Asset loading with webpack inlining
│ ├── TutorialHand.ts # Tutorial pointer helper
│ └── Effects.ts # Fade effects
├── utils/
│ ├── EventsSystem.ts # Global event bus (redirectToStore)
│ └── Sound.ts # Sound manager (Howler wrapper)
├── controllers/
│ └── CameraController.ts # Camera viewport + attachedToCamera support
├── configs/
│ └── AssetsInlineHelper.ts # Spine animation imports
├── data/
│ ├── assets.ts # Asset manifest (sprites, sounds, fonts)
│ ├── gameData.ts # Game configuration
│ └── localizationData.ts # Text localization
└── assets/
├── sprites/ # Image assets (use WebP!)
│ └── gui/ # UI elements
└── art/
└── Animations/ # Spine animations (.skel binary!)
Use screen anchors and percentage-based offsets for responsive positioning:
import { AdaptiveSprite, AdaptiveGroup } from './helpers/Adaptive';
// Button at bottom-center, 15% from bottom
const button = new AdaptiveSprite('play_button');
button.setScreenAnchor('bottom-center');
button.setOffset(0, -15, '%', '%');
button.setWidth(40, '%');
// Portrait/landscape differences
button.setLandscapeConfig({ width: 25, offsetX: -10 });
// Resize handler
button.resize(canvasWidth, canvasHeight);Screen anchors: top-left, top-center, top-right, middle-left, center, middle-right, bottom-left, bottom-center, bottom-right
See docs/ADAPTIVE_LAYOUT_SYSTEM.md for complete guide.
For UI elements that should move with camera:
import { CameraController } from './controllers/CameraController';
const camera = new CameraController();
button.setAttachedToCamera(true);
button.setCamera(camera);For simpler cases, use fixed virtual coordinates:
new ScaledSprite('texture', {
portraitX: 540, portraitY: 960, portraitScale: 1,
landscapeX: 960, landscapeY: 540, landscapeScale: 0.8,
});Trigger store redirect:
import eventsSystem from './utils/EventsSystem';
eventsSystem.emit('redirectToStore');- Define assets in
src/data/assets.ts - Define Spine animations in
src/configs/AssetsInlineHelper.ts - Assets are automatically inlined by webpack
CRITICAL: Always use binary .skel format, NOT JSON!
Binary format is 5-10x smaller. See docs/SPINE_WORKFLOW.md.
npm run build- Open
dist/index.htmlin browser - Use DevTools to test different screen sizes
Upload to: https://p.applov.in/playablePreview?create=1
See docs/ADAPTIVE_TESTING.md for complete testing guide.
- PixiJS 8 - 2D WebGL rendering
- @smoud/playable-sdk - Ad network SDK integration
- @esotericsoftware/spine-pixi-v8 - Spine animations
- GSAP - Animation tweening
- Howler - Sound management
- TypeScript - Type safety
- Add your assets to
src/assets/sprites/(WebP format) - Update
src/data/assets.tswith asset definitions - Edit
src/scenes/MainScene.tswith your game logic - Use AdaptiveSprite/AdaptiveGroup for responsive positioning (recommended)
- Use
attachedToCamerafor UI elements that should move with camera - Test in portrait AND landscape modes
- Verify file size is under 5MB
- Test with AppLovin preview before submitting