Scope and Hard Boundaries
This Skill only handles Banner, interstitial, and rewarded video ad capabilities for Phaser 4 + TypeScript/Vite + Capacitor mobile projects, with the mediation layer fixed to AppLovin MAX and the integration implementation fixed to the officially maintained AppLovin cordova-plugin-applovin-max, loaded by Capacitor's Cordova compatibility layer. The project only establishes a business facade and an official plugin API adapter on the TypeScript side; it does not build its own Android/iOS ad plugin, nor does it directly integrate the MAX native SDK. All configured ad placements maintain state independently; interstitials and rewarded videos are only silently preloaded in the background, and ad objects or views are not actively created during the initialization phase; the plugin manages loading resources on demand internally. Successful preloading of interstitials and rewarded videos is determined by the readiness property of the current ad instance object; the loaded callback and business phase cannot alone prove success. Full-screen display reads the instance readiness property and existing business state and returns immediately; Banner is not preloaded and is only created and loaded when the business requests display; when Banner is supported, the ad placement is enabled, and the page allows display, the ad area is reserved before the page's first frame and UI layout is completed, without waiting for ad load or display. Each ad placement independently maintains a load failure count, retry deadline, and at most one retry timer, but uses the same classification, backoff, pause, and resume rules. Before starting any design, implementation, or review, the sole detailed contract must first be read AppLovin MAX Integration Contract, and the state, timing, failure, and compliance rules therein shall govern.
- Phaser Web, browser preview, and mini-games do not directly call MAX, nor do they load the native ad SDK; on these runtime targets the ad capability must be an explicit
unsupported/no-op, returning immediately after the call and continuing the game. - iOS and Android only use AppLovin's official
cordova-plugin-applovin-maxBefore implementation, you must check according toofficial Cordova integration documentationandofficial repositorythe plugin version, Capacitor Cordova compatibility layer, Android Gradle, and iOS package manager; if incompatible, block and report, and do not fall back to community plugins, a self-built Capacitor native plugin, or business code directly connecting to the MAX SDK. - This Skill does not automatically configure the MAX console, ad network accounts, store metadata, or release channels for the project. SDK keys and ad unit IDs are injected into the official plugin adapter layer from controlled build configuration per environment, and are not hardcoded into business source code, examples, logs, or commit records; ad network account credentials and Ad Review keys must not enter Web code or public artifacts.
- Ads are only attempted at natural interruption points; the caller never waits for ad loading, network requests, or display completion. When an ad cannot be displayed, the result must be returned immediately according to the current state of the ad placement, and must not block scene transitions, input, the main loop, or settlement flow. Background loading, load failures, and retries remain silent, with no Toast.
- When a video ad placement is triggered for display by the user but is currently unavailable, or after the official plugin accepts the display and then calls back
displayFailed, a single "Video ad temporarily unavailable, please try again later" Toast is shown through the unified UI layer; the plugin adapter layer must not directly manipulate Phaser UI, and repeated callbacks must not cause repeated prompts. - The privacy popup must always use MAX's built-in Terms and Privacy Policy Flow and its integrated Google UMP; before initialization, enable the flow and configure the privacy policy URL, then call MAX initialize to start the built-in flow; on the user side, first complete the MAX privacy popup; whether consent is given or denied, continue to complete initialization, based on the SDK initialization completion callback. Keep initializing during the popup; do not initiate a second initialization or retry. Do not create a separate Phaser/Web privacy popup or an independent CMP flow; iOS ATT is handled by this flow according to the official configuration to avoid duplicate requests. The specific plugin configuration and initialization callback semantics are subject to the detailed contract.
- Banner does not participate in initialization preloading; the native view is created and loaded only on the first request for display, and the call returns immediately. Display when loaded is received, the layout is safe, and the business still requests visibility; on creation or loading failure, remain hidden and continuously retry with the same independent backoff; upon leaving the display scene, clear the visibility request and cancel retries, and old callbacks must not resume creation or display. Do not show a Toast, do not occupy error height, and do not wait for loading.
Global control access
$phaser4-game-workflow-control is the only global state, risk gate, task scope, and evidence control plane. This domain may propose solutions, review the current state, and implement within the current Work Item, the frozen Implementation Package, A level, and path scope; all plans, changes, test evidence, and blockers must be registered and reviewed back at the control plane. When adjusting interfaces, paths, or verification scope within a task, update the Work Item accordingly and do not create a parallel state machine.
A4-A6 actions involving external writes, payments, real devices, store submission, publishing, or irreversible operations must obtain explicit approval from the control plane on a per-object basis; this Skill does not approve, execute, or push these actions on behalf of others, nor does it automatically initiate real-device acceptance runs. Ordinary local documents, bridge code, and unit tests are executed under the current task authorization.
Delivery process
- Read the current Work Item, the project TDD/dependency capability profile, the Capacitor platform status, and the official plugin installation status; according to AppLovin MAX integration contractregister the scope, non-goals, public interfaces, state ownership, lifecycle, and failure boundaries. Advertising is an optional commercial capability and must not be treated as a runtime prerequisite for the Phaser Web core loop.
- Submit a minimal module proposal: Web/mini-game no-op, the official AppLovin Cordova plugin, a shared TypeScript business facade and plugin API adapter, and test doubles. Verify the official plugin release version, license, Android/iOS support, Capacitor compatibility approach, callback semantics, and privacy capabilities; do not propose community plugins or a self-built native bridge as a fallback implementation.
- Freeze the plugin adapter contract:
initialize、preload(slotId)、tryShow(context)、setBannerVisibility(slotId, visible)、isReady(slotId)are all non-blocking calls and return structured results; the adapter normalizes the official plugin's callback/event API into this contract. Initialization failure entersfailed: Explicit transient failures are continuously backed off by the service's sole initialization retry task at 2/4/8/16/32/64 seconds; paused when background, offline, or host conditions are not met, and resumed after recovery; explicitly retried after configuration or dependency errors are corrected. Initialization retries are isolated from ad unit loading retries, and timers or counters are not mixed. Service initialization is idempotent; when the platform is supported and the service is enabled and the plugin configuration is valid, MAX initialization must be initiated, without privacy consent, CMP completion, or ATT authorization as a precondition for the call. Each ad unit has only one business state owner, and native format objects are managed internally by the official plugin. After successful initialization, all enabled interstitial and rewarded video preload intents are delivered immediately, and actual loading passes through the ad request privacy gate; all initiated load failures are continuously scheduled by each ad unit's own retry timer, without terminating by error category and without a retry count limit, until success; disabling, removal, or service destruction terminates retries, and runtime gates being closed only pauses them. Each ad unit independently stores its count and deadline, and applies the same set of2/4/8/16/32/64 秒backoff, jitter, deduplication, background/offline pause, and resume rules. Canceling, reordering, or triggering a retry for one ad unit must not change the timers of other ad units. - Register responsible parties separately for the MAX console, the official plugin and its native dependencies, the Capacitor Cordova compatibility configuration, MAX's built-in privacy flow/Google UMP/ATT, ad unit configuration, and telemetry. The fixed aggregation channels are AppLovin, Google AdMob, Mintegral, Pangle, Unity Ads, DT Exchange (Fyber), and Verve (PubNative/HyBid); the version combinations of the plugin, MAX SDK, and adapters are subject to the compatibility ranges currently declared by the official plugin and official channel documentation, and version numbers are not hardcoded in the Skill or business code, nor is the MAX SDK repeatedly introduced bypassing the plugin.
- Call at natural interruption points
tryShow; the call reads the readiness property and business snapshot of the currently valid instance of the specified ad unit, and never triggers foreground loading. After the matching rewarded videohiddencallback arrives, the ad service uses a monotonic clock to record a 30-second interstitial protection deadline; interstitialtryShowwithin the protection period must immediately returnrewarded-interstitial-delay, and must not call MAX show, create a cooldown timer, or pop up an unavailable Toast. After the protection period ends, as long as the target ad unit is ready, all gates are open, and the natural interruption conditions hold, display can be initiated. If not ready, the same ad unit is currently displaying, privacy is pending, the network is unavailable, or the platform is unsupported, return immediately and continue the game; when a video ad is unavailable or display fails, the unified UI layer consumes the structured result/event and displays an unavailable Toast once. Rewards are granted asynchronously only by the matchingrewardedcallback and remain idempotent; after closing or display failure, immediately silently preload the corresponding full-screen ad unit. - When entering a page that can display a Banner, first determine the reserved size and content inset according to the current platform format, available width, and safe area, and complete the UI layout before the page's first frame; layout planning does not create an ad view or request an ad. When the Banner is displayed, it is placed only in the reserved area and does not adjust the game UI; when the actual size cannot be safely accommodated, it remains hidden and is handled in the next page or viewport layout cycle. The Banner uses a native ad view; the business only controls show/hide and does not create its own refresh timer. Pause refresh when hidden, switched to the background, or the page does not allow ads, and resume according to the contract when display resumes; do not cover game buttons, gesture areas, or system safe areas, or treat a blank placeholder as a loaded ad.
- First complete static review, TypeScript/native compilation, and state machine unit tests, then run platform integration tests in an authorized target environment. Use MAX Test Mode and Mediation Debugger to verify separately by channel and format, checking
app-ads.txt, iOS SKAdNetwork, Google CMP/TCF and ATT; do not pass off success with a single network or a single format as full coverage. - Submit the candidate diff, interface contract, platform logs (redacted), failure retry traces and verification results to
$phaser4-game-workflow-control; list unexecuted external configuration, physical devices, live ads and release steps as explicit uncovered items.
Minimum public contract
The shared facade must provide at least the following semantics; specific parameter naming may follow the target project's conventions, but the return timing must not be changed:
initialize(config): Promise<InitResult> // 只确认桥接请求受理/初始化状态,不等待广告加载
retryInitialize(): Promise<InitResult> // 手动入口复用初始化恢复任务,不绕过退避或配置阻断
preload(slotId): Promise<PreloadResult> // 仅插页/激励后台加载;Banner 返回 format-mismatch
isReady(slotId): ReadyResult // 全屏读取实例就绪属性;Banner 读取加载状态,不创建或加载
tryShow(context): Promise<ShowResult> // 复核实例就绪属性和业务门,通过后才展示
setBannerVisibility(slotId, visible): Promise<BannerVisibilityResult> // 展示时按需创建/加载,立即返回
The result must contain at least the stable ok、code、platform、phase、gates and the necessary retryScheduled fields; when an interstitial is skipped due to the 30-second protection period after a rewarded video, return rewarded-interstitial-delay and interstitialDelayRemainingMs. Business callers only pass the environment, capability switches and business slotId; the official plugin adapter resolves the SDK key and MAX ad unit ID by environment and uses them only at the plugin API boundary. Plugin raw exceptions, device IDs, ad network account credentials or full waterfall credentials must not be passed through to the business layer.tryShow returning "show requested" does not equal a successful impression.
InitResult、PreloadResult、ReadyResult、ShowResult and NativeAdEvent 's minimum fields, privacy gate/result codes,instanceGeneration/showRequestId association and duplicate event idempotency rules are uniformly defined by theintegration contract.
Delivery review checklist
- Platform boundaries: Web/mini-game calls are no-ops; Android/iOS call MAX only through the official AppLovin Cordova plugin, with no community plugins, self-built native ad plugins or direct SDK integration introduced; host page lifecycle, Activity/ViewController and foreground/background transitions are clearly defined.
- Lifecycle: initialization is idempotent; each configured ad placement holds a business phase, load count, retry deadline and at most one load retry timer, and format-matching native objects are managed by the official plugin; the ad service additionally holds the 30-second interstitial protection deadline after a rewarded video ends, but does not create a timer for this. All ad placements share service-level gates such as this cross-format protection state, do not share load retry timers, and no cross-placement fullscreen mutual exclusion is set; instance rebuilds increment
instanceGeneration, and show requests generate a uniqueshowRequestId; a successful initialization immediately delivers all enabled interstitial and rewarded video preload intents, actual loading passes through the ad request privacy gate, and repeated calls will not request concurrently. - Native gates: Activity/ViewController provider, foreground state, network connectivity and privacy readiness are native service dependencies;
phaseonly represents the ad resource/display phase, and gate states are computed independently, not mixed into Phaser scene state. - Pacing: interstitials are shown only at natural break points; a matching rewarded video
hiddenevent blocks interstitials for 30 seconds from its monotonic timestamp, and the protection period only blocks interstitials, not Banner, rewarded video, background preload or reward settlement. During the protection period, immediately and silently return the remaining milliseconds; after expiry, the decision resumes without needing a timer wakeup;hiddenanddisplayFailedboth trigger background preload for the corresponding ad placement. - Readiness determination: the readiness property of a fullscreen ad instance is the sole basis for successful preload; the adapter reads the plugin's internal instance state via the official isInterstitialReady/isRewardedAdReady, and does not store a separate ready boolean. loaded only triggers re-verification; before show and retry, re-read, and if the instance does not exist, is invalid or the read fails, it is considered not ready; Banner is still managed by the load event after creation and does not participate in preload.
- Initialization recovery: the service has at most one initialization request and one pending retry timer; transient failures back off continuously, host/foreground/network gate closures preserve the deadline, privacy status does not pause initialization retries, and recovery deduplicates scheduling; configuration errors are not retried automatically. Success, disabling, or destruction cleans up the initialization recovery task; after success, the fullscreen preload intent is delivered only once, ad requests still check the privacy gate, and when blocked the intent is retained pending recovery.
- Failure recovery: each ad placement uses an independent load retry timer and follows the same backoff formula to keep retrying until success, with no upper limit on attempts; counts, deadlines, timer references, and in-flight markers are all isolated per ad placement, and only one pending timer is allowed per ad placement. In the background or offline, they are paused separately, and after recovery each due ad placement is restored at most once; display failures are recorded independently and preloaded again, without entering another retry logic.
- User feedback: background loading, retries, and status changes remain silent; video ad display triggers when immediately determined unavailable or asynchronously
displayFailedonly shows a localized unavailable Toast once, and repeated/late callbacks do not trigger the prompt again;rewarded-interstitial-delayis expected pacing control and does not show an unavailable Toast. - Banner: not preloaded, not created by default; the first display request creates and loads it, and creation failure and load failure share one continuous backoff retry task; leaving the display scene immediately cancels the task and invalidates old requests, and re-entering requires requesting display again; when ready and the layout is safe, it is displayed according to the currently visible request, and on failure it stays hidden with no Toast; before the page's first frame, the area is reserved according to the platform Banner size rules and safe area, and loading, failure, retry, and visibility callbacks do not change the content inset; the actual size is only used to verify whether it can safely fit into the reserved area, and the layout does not block game interaction; refresh has only one owner, and JS/Phaser are prohibited from creating their own refresh timers.
- Compliance and security: MAX's built-in privacy flow and its Google UMP/TCF configuration, MAX privacy flags, iOS ATT, SKAdNetwork, Google requirements, and target region rules all have owners and evidence; SDK keys and ad placements come from controlled environment-specific build configurations and are used only by the official plugin adapter, account credentials and Ad Review keys do not enter the Web layer, and telemetry is desensitized.
- Verification: each fixed network is individually confirmed in test mode or the Mediation Debugger for the adapter, loading, display, and official plugin failure callback; check MAX waterfall,
app-ads.txtand the pre-release platform checklist. Unit tests must also cover that when the official plugin ad event never returns, settlement still continues via fire-and-forget, and that the adapter Promise only waits for local acceptance/rejection, not for ad events.
This repository this time delivers only the Skill guidance document, with no new runtime code, scripts, SDK dependencies, or external configuration.