@maccesar/titools 5.1.1 → 5.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/CONTRIBUTING.md +69 -0
  2. package/README.md +112 -72
  3. package/agents/ti-pro.md +5 -1
  4. package/commands/ti-audit.md +5 -1
  5. package/docs/examples.md +91 -0
  6. package/docs/knowledge-index.md +57 -0
  7. package/lib/config.js +2 -0
  8. package/lib/downloader.js +1 -1
  9. package/package.json +4 -2
  10. package/skills/purgetss/references/multi-density-images.md +1 -1
  11. package/skills/ti-admob-unified/SKILL.md +58 -0
  12. package/skills/ti-admob-unified/agents/openai.yaml +4 -0
  13. package/skills/ti-admob-unified/assets/example/app.js +1207 -0
  14. package/skills/ti-admob-unified/assets/example/lib/ads.js +646 -0
  15. package/skills/ti-admob-unified/assets/example/library-usage.js +136 -0
  16. package/skills/ti-admob-unified/references/api-reference.md +615 -0
  17. package/skills/ti-admob-unified/references/banners.md +435 -0
  18. package/skills/ti-admob-unified/references/contributing.md +233 -0
  19. package/skills/ti-admob-unified/references/dependencies.md +91 -0
  20. package/skills/ti-admob-unified/references/fullscreen.md +238 -0
  21. package/skills/ti-admob-unified/references/game-monetization.md +148 -0
  22. package/skills/ti-admob-unified/references/getting-started.md +319 -0
  23. package/skills/ti-admob-unified/references/index.md +33 -0
  24. package/skills/ti-admob-unified/references/integration.md +87 -0
  25. package/skills/ti-admob-unified/references/library.md +220 -0
  26. package/skills/ti-admob-unified/references/mediation-parity.md +17 -0
  27. package/skills/ti-admob-unified/references/mediation.md +145 -0
  28. package/skills/ti-admob-unified/references/migration.md +259 -0
  29. package/skills/ti-admob-unified/references/module-changelog.md +84 -0
  30. package/skills/ti-admob-unified/references/module-license.txt +21 -0
  31. package/skills/ti-admob-unified/references/privacy.md +281 -0
  32. package/skills/ti-admob-unified/references/production.md +67 -0
  33. package/skills/ti-admob-unified/references/rewarded-interstitial.md +101 -0
  34. package/skills/ti-admob-unified/references/roadmap.md +143 -0
  35. package/skills/ti-admob-unified/references/source-notes.md +80 -0
  36. package/skills/ti-admob-unified/references/source-snapshot.json +644 -0
  37. package/skills/ti-admob-unified/references/third-party-notices.md +22 -0
  38. package/skills/ti-game/SKILL.md +31 -5
  39. package/skills/ti-game/references/api.md +36 -24
  40. package/skills/ti-game/references/debugging-performance.md +22 -7
  41. package/skills/ti-game/references/examples.md +113 -20
  42. package/skills/ti-game/references/input.md +101 -0
  43. package/skills/ti-game/references/patterns.md +56 -10
  44. package/skills/ti-game/references/physics.md +530 -0
  45. package/skills/ti-game/references/project-setup.md +131 -47
  46. package/skills/ti-game/references/recipes-action.md +149 -18
  47. package/skills/ti-game/references/recipes-adventure-effects.md +47 -4
  48. package/skills/ti-game/references/roadmap.md +11 -4
  49. package/skills/ti-game/references/source-notes.md +81 -0
  50. package/skills/ti-game/references/tilemaps.md +13 -4
  51. package/skills/ti-game-assets/SKILL.md +53 -0
  52. package/skills/ti-game-assets/agents/openai.yaml +4 -0
  53. package/skills/ti-game-assets/references/alpha.md +26 -0
  54. package/skills/ti-game-assets/references/art-direction.md +37 -0
  55. package/skills/ti-game-assets/references/integration.md +49 -0
  56. package/skills/ti-game-assets/references/manifest.example.json +429 -0
  57. package/skills/ti-game-assets/references/manifest.md +39 -0
  58. package/skills/ti-game-assets/references/offline-audio.md +33 -0
  59. package/skills/ti-game-assets/references/prompts.md +33 -0
  60. package/skills/ti-game-assets/references/repeating-textures.md +17 -0
  61. package/skills/ti-game-assets/references/responsible-ads.md +31 -0
  62. package/skills/ti-game-assets/references/sound-assets.md +42 -0
  63. package/skills/ti-game-assets/references/vector-sources.md +21 -0
  64. package/skills/ti-game-assets/scripts/alpha_tools.py +160 -0
  65. package/skills/ti-game-assets/scripts/requirements.txt +1 -0
  66. package/skills/ti-game-assets/scripts/validate_manifest.py +267 -0
  67. package/skills/ti-synthengine/SKILL.md +77 -67
  68. package/skills/ti-synthengine/assets/example/README.md +84 -0
  69. package/skills/ti-synthengine/assets/example/app.js +1178 -0
  70. package/skills/ti-synthengine/assets/example/lib/sequenceOwner.js +83 -0
  71. package/skills/ti-synthengine/assets/example/lib/sequenceScore.js +25 -0
  72. package/skills/ti-synthengine/references/advanced-examples.md +174 -0
  73. package/skills/ti-synthengine/references/android-sim80-correction-evidence.zip +0 -0
  74. package/skills/ti-synthengine/references/android-sim80-correction.json +162 -0
  75. package/skills/ti-synthengine/references/api.md +573 -153
  76. package/skills/ti-synthengine/references/audio-engine.md +272 -124
  77. package/skills/ti-synthengine/references/bypass-physical-recheck-evidence.zip +0 -0
  78. package/skills/ti-synthengine/references/examples.md +355 -106
  79. package/skills/ti-synthengine/references/frontier-android-evidence.zip +0 -0
  80. package/skills/ti-synthengine/references/frontier-ipad-evidence.zip +0 -0
  81. package/skills/ti-synthengine/references/frontier-physical-validation.json +1918 -0
  82. package/skills/ti-synthengine/references/guide.md +426 -75
  83. package/skills/ti-synthengine/references/performance-review-evidence.zip +0 -0
  84. package/skills/ti-synthengine/references/performance-review.json +1146 -0
  85. package/skills/ti-synthengine/references/physical-validation.json +1457 -0
  86. package/skills/ti-synthengine/references/recipes-interaction.md +549 -0
  87. package/skills/ti-synthengine/references/recipes.md +434 -420
  88. package/skills/ti-synthengine/references/recommendations.md +72 -85
  89. package/skills/ti-synthengine/references/sound-design.md +375 -155
  90. package/skills/ti-synthengine/references/source-notes.md +109 -0
  91. package/skills/ti-synthengine/references/source-snapshot.json +452 -0
  92. package/skills/ti-synthengine/references/stats-performance.json +2992 -0
  93. package/skills/ti-synthengine/references/stats-performance.md +82 -0
  94. package/skills/ti-synthengine/references/studio-validation.json +6202 -0
  95. package/skills/ti-synthengine/references/troubleshooting.md +123 -78
  96. package/skills/ti-synthengine/references/unified-bypass-performance.json +22425 -0
  97. package/skills/ti-synthengine/references/unified-validation.json +314 -0
  98. package/AGENTS-VERCEL-RESEARCH.md +0 -175
@@ -0,0 +1,91 @@
1
+ > Source snapshot: official ti.admob.unified 1.0.0 documentation at release source commit `034843299b2984253988e0ffccb9f6a1c91682c9` (copied 2026-10-24). Relative links rebased for this skill.
2
+
3
+ # Dependency inventory
4
+
5
+ The core and five optional complements use the published SDK and adapter pairs verified on October 23, 2026. Each module has its own iOS Podfile, lockfile and framework checksum inventory. Android pins live in each module's `android/build.gradle`.
6
+
7
+ The latest published Google adapters determine the network SDK versions. Meta iOS SDK `6.22.1` and InMobi Android SDK `11.5.1` are available independently, but their current Google adapters pin `6.22.0` and `11.5.0` respectively; those tested pairs are retained. Do not replace a network SDK independently of its adapter. InMobi Android adapter `11.5.0.1` is available as an AAR and POM in Google's Maven repository, although its documentation heading still says "In progress".
8
+
9
+ Google currently lists GMA iOS `13.x` and Android `25.x` as supported. Check both the [iOS sunset schedule](https://developers.google.com/admob/ios/deprecation) and [Android sunset schedule](https://developers.google.com/admob/android/deprecation), plus SDK/provider advisories, before distributing an app update. A supported major version and a store-specific SDK warning are separate checks; review any warning against the final app's resolved dependencies.
10
+
11
+ ## iOS vendored XCFrameworks: `ti.admob.unified`
12
+
13
+ | Component | Framework | Version |
14
+ | ----------------------- | ----------------------------------- | -------: |
15
+ | Google Mobile Ads | `GoogleMobileAds.xcframework` | `13.11.0` |
16
+ | User Messaging Platform | `UserMessagingPlatform.xcframework` | `3.1.0` |
17
+
18
+ ## iOS per-network complements
19
+
20
+ The eleven frameworks are stored without duplication under `mediation/<network>/ios/platform/`: AppLovin (2), Meta (2), InMobi (2), Unity (3), Liftoff (2). Unity Ads 4.21.0 no longer requires IronSourceAdQualitySDK. No ironSource advertising adapter or SDK is distributed.
21
+
22
+ | Component | Framework | Version |
23
+ | ------------------------- | ------------------------------------ | -----------: |
24
+ | AppLovin adapter | `AppLovinAdapter.xcframework` | `13.6.4.0` |
25
+ | AppLovin SDK | `AppLovinSDK.xcframework` | `13.6.4` |
26
+ | Meta adapter | `MetaAdapter.xcframework` | `6.22.0.0` |
27
+ | Meta Audience Network SDK | `FBAudienceNetwork.xcframework` | `6.22.0` |
28
+ | InMobi adapter | `InMobiAdapter.xcframework` | `11.5.0.0` |
29
+ | InMobi SDK | `InMobiSDK.xcframework` | `11.5.0` |
30
+ | Unity adapter | `UnityAdapter.xcframework` | `4.21.0.0` |
31
+ | Unity Ads SDK | `UnityAds.xcframework` | `4.21.0` |
32
+ | Unity support library | `UnityCoherenceLib.xcframework` | `0.2.0` |
33
+ | Liftoff Monetize adapter | `LiftoffMonetizeAdapter.xcframework` | `7.7.8.0` |
34
+ | Vungle Ads SDK | `VungleAdsSDK.xcframework` | `7.7.8` |
35
+
36
+ The version column is the pinned CocoaPods version; lockfiles record the resolved adapter and SDK pair. Meta now uses SDK 6.22.0 on both platforms. Liftoff uses SDK 7.7.8 on iOS and 7.7.9 on Android. The version contract test records this difference and checks the networks whose versions match.
37
+
38
+ The official CocoaPods specifications resolve the adapter and matching network SDK pairs. Each module has its own `ios/install_frameworks.sh`: it downloads that module's exact Podfile versions, stages its framework set, verifies its tree hashes, and restores the previous platform directory if validation fails. Run `ios/install_frameworks.sh` for the two core frameworks and `mediation/<network>/ios/install_frameworks.sh` for one complement. Complement installers use `pod install --deployment` to preserve the locked resolution.
39
+
40
+ The tree checksum is calculated from the sorted list of relative file paths and the SHA-256 of every file in the XCFramework:
41
+
42
+ ```sh
43
+ find . -type f -print0 | LC_ALL=C sort -z | xargs -0 shasum -a 256 |
44
+ shasum -a 256
45
+ ```
46
+
47
+ ## Android Maven dependencies: `ti.admob.unified`
48
+
49
+ Declared in `android/build.gradle`.
50
+
51
+ | Coordinate | Version |
52
+ | ------------------------------------------------ | ------: |
53
+ | `com.google.android.gms:play-services-ads` | 25.5.0 |
54
+ | `com.google.android.ump:user-messaging-platform` | 4.0.0 |
55
+ | `com.google.guava:guava` | 33.7.2-android |
56
+
57
+ ## Android per-network complements
58
+
59
+ Declared separately in `mediation/<network>/android/build.gradle`; `meta` uses the `facebook` coordinate and `liftoff` uses `vungle`.
60
+
61
+ | Coordinate | Version |
62
+ | ----------------------------------- | -------: |
63
+ | `com.google.ads.mediation:facebook` | 6.22.0.1 |
64
+ | `com.google.ads.mediation:inmobi` | 11.5.0.1 |
65
+ | `com.google.ads.mediation:unity` | 4.21.0.0 |
66
+ | `com.google.ads.mediation:applovin` | 13.6.4.2 |
67
+ | `com.google.ads.mediation:vungle` | 7.7.9.0 |
68
+
69
+ Each complement declares its adapter coordinate. Unity also explicitly declares `com.unity3d.ads:unity-ads:4.21.0`: Google's adapter POM does not bring the Unity SDK transitively. Both entries must reach the packaged POM and consumer graph. See Google's [Unity Android integration guide](https://developers.google.com/admob/android/mediation/unity).
70
+
71
+ InMobi, Liftoff and Unity also pin `com.squareup.okhttp3:okhttp:5.4.0` and `com.squareup.okio:okio:3.18.2`. OkHttp 5.4.0 requires compile SDK 36, provided by the declared minimum Titanium 13.4.1.GA. OkHttp 5.5.x requires compile SDK 37 and remains incompatible with this stable Titanium toolchain. Okio fixes base64 compatibility with callers compiled against pre-3.18 releases. These utility dependencies add no ad networks. The core pins Guava `33.7.2-android` for its deserialization allocation fix. Unity Ads 4.21.0 requests OkHttp 3.12.13 and Okio 1.15.0 without these overrides; both matched advisories during the isolated-consumer scan. Generated POMs propagate the reviewed versions into consumer applications.
72
+
73
+ ## Update policy
74
+
75
+ All six modules remain at version `1.0.0`. Dependency updates require rebuilding both platform ZIPs for every discovered module, validating checksums, checking isolated consumer combinations and testing on available devices. Verify third-party delivery separately with configured accounts and Ad Inspector.
76
+
77
+ ## Transitive security review
78
+
79
+ The October 23 refresh updates the direct utility overrides as well as the ad SDKs:
80
+
81
+ | Dependency | Previous pin | Current pin | Modules |
82
+ | --- | --- | --- | --- |
83
+ | Guava | `33.7.1-android` | `33.7.2-android` | Core |
84
+ | OkHttp | `4.12.0` | `5.4.0` | InMobi, Liftoff, Unity |
85
+ | Okio | Transitive, including `3.6.0` / `3.7.0` | `3.18.2` | InMobi, Liftoff, Unity |
86
+
87
+ Guava's [33.7.2 release](https://github.com/google/guava/releases/tag/v33.7.2) documents the allocation fix. OkHttp's [changelog](https://lysine.dev/okhttp/changelogs/changelog/) documents later releases, but 5.4.0 is the latest compatible pin because of the Android AAR compile-SDK requirements above. The 5.5.1 certificate-blocklist change is not included in this compatible pin; runtime OS support and compile-SDK requirements are separate constraints. The [Okio changelog](https://lysine.dev/okio/changelog/) describes the 3.18.2 compatibility correction.
88
+
89
+ The October 23 [OSV querybatch](https://google.github.io/osv.dev/api/) scan covered 151 distinct resolved Maven name/version pairs across eight configurations: core, each complement, AppLovin + Unity, and all networks. No matches remained after the Unity utility overrides. The earlier September scan describes the old matrix. Dependency scanning and successful linking do not establish provider ad delivery.
90
+
91
+ Unity `4.21.0.0` includes the adapter consent-forwarding update. Provider-side verification is described in the [mediation guide](mediation.md#unity-consent-with-the-pinned-adapter).
@@ -0,0 +1,238 @@
1
+ > Source snapshot: official ti.admob.unified 1.0.0 documentation at release source commit `034843299b2984253988e0ffccb9f6a1c91682c9` (copied 2026-10-24). Relative links rebased for this skill.
2
+
3
+ # Fullscreen ads
4
+
5
+ Interstitial, rewarded, rewarded interstitial and app open proxies share one public lifecycle and event contract on iOS and Android.
6
+
7
+ ## When to show a fullscreen ad
8
+
9
+ A fullscreen ad interrupts the current screen, so choose its presentation point before requesting it.
10
+
11
+ Load early, show later: `load()` is a network request and can take seconds. Start it before the intended break, for example when a level opens, an article starts or a form appears. Call `show()` when the application reaches that break. Do not present unconditionally from the `loaded` listener: that lets network timing determine when the user is interrupted. A screen may instead keep an explicit Show request pending during loading, provided it cancels that request when the user leaves or the app loses the foreground.
12
+
13
+ Show fullscreen ads at a natural break, such as between levels or after a task or flow ends. Avoid interrupting work in progress.
14
+
15
+ Google's guidance includes these restrictions:
16
+
17
+ - Do not show an interstitial as the app opens. That moment belongs to the App Open format, documented below.
18
+ - Do not show one on the way out, when the user is already leaving.
19
+ - Do not interrupt an action in progress, or place the ad where a button or a control the user was about to touch used to be.
20
+ - Use `createRewarded()` or the dedicated `createRewardedInterstitial()` format for rewards. Ordinary interstitials must not offer rewards.
21
+ - Avoid consecutive interstitials and excessive frequency. Configure the ad unit's frequency cap in the AdMob console; it is not a JavaScript setting.
22
+
23
+ See the full restrictions in Google's [Android interstitial guide](https://developers.google.com/admob/android/interstitial) and [iOS interstitial guide](https://developers.google.com/admob/ios/interstitial).
24
+
25
+ ## Privacy gate
26
+
27
+ Fullscreen proxies do not call UMP and do not enforce ad eligibility:
28
+
29
+ ```js
30
+ if (!Admob.canRequestAds()) {
31
+ return
32
+ }
33
+ ```
34
+
35
+ Create and load fullscreen ads only after `module_initialized` succeeds.
36
+
37
+ ## Interstitial
38
+
39
+ Load the ad ahead of its presentation point:
40
+
41
+ ```js
42
+ const interstitial = Admob.createInterstitial({
43
+ adUnitId: Admob.TEST_INTERSTITIAL,
44
+ autoReload: false
45
+ })
46
+
47
+ interstitial.addEventListener(Admob.AD_LOADED, () => {
48
+ Ti.API.info('Interstitial is ready for the next break')
49
+ })
50
+
51
+ interstitial.addEventListener(Admob.AD_FAILED_TO_LOAD, event => {
52
+ Ti.API.warn(`Interstitial failed: ${event.error} (${event.code})`)
53
+ })
54
+
55
+ interstitial.load()
56
+ ```
57
+
58
+ Then present it when the application reaches the break it chose:
59
+
60
+ ```js
61
+ function onLevelCompleted() {
62
+ if (interstitial && interstitial.isLoaded()) {
63
+ interstitial.show()
64
+ }
65
+
66
+ goToNextLevel()
67
+ }
68
+ ```
69
+
70
+ If the ad is not ready, let the application continue and try at the next break.
71
+
72
+ The executable [example app](../assets/example/app.js) loads automatically after initialization. Each format has one button that reports its state and enables Show when ready. One Show or Retry tap is enough: if an ad needs loading or replacement after a size change, the example waits and presents when it arrives. The rewarded interstitial card explains the reward and AdMob’s introduction requirements, links to the official policy and opens a Watch test ad/Skip introduction after Show. Watch permits presentation; Skip cancels it. Watch also remains valid through a required size replacement, so loading does not require another Show tap. Closing an ad preloads another without presenting it. Leaving the foreground, closing the window, changing privacy eligibility or requesting a different fullscreen cancels the pending presentation.
73
+
74
+ ## Rewarded
75
+
76
+ Reward the user only from the `rewarded` event:
77
+
78
+ ```js
79
+ const rewarded = Admob.createRewarded({
80
+ adUnitId: Admob.TEST_REWARDED,
81
+ autoReload: false
82
+ })
83
+
84
+ rewarded.addEventListener(Admob.AD_REWARDED, event => {
85
+ grantReward(event.rewardAmount, event.rewardType)
86
+ })
87
+
88
+ rewarded.addEventListener(Admob.AD_FAILED_TO_SHOW, event => {
89
+ Ti.API.warn(`Rewarded ad could not show: ${event.error}`)
90
+ })
91
+
92
+ rewarded.load()
93
+ ```
94
+
95
+ Present it only after the user accepts a clear reward offer, using `isLoaded()` before `show()`. Closing a rewarded ad is not proof that the reward was earned. Keep the reward handler alive until the SDK delivers the result; mediated callback ordering may differ. Version `1.0.0` exposes client-side rewards only; it has no server-side verification configuration.
96
+
97
+ The application must coordinate fullscreen proxies so only one presentation is active at a time. Keep it separate from UMP, ATT and Ad Inspector.
98
+
99
+ ## Rewarded interstitial
100
+
101
+ `createRewardedInterstitial()` shares Rewarded's configuration, methods and reward event. Before presentation, explain the reward and offer a way to skip. The proxy does not show that introduction itself. See [Rewarded interstitial ads](rewarded-interstitial.md) for the complete flow.
102
+
103
+ ## App open
104
+
105
+ Use an app open ad when the application enters the foreground, either at a cold start or when returning from the background. Load it beforehand and present it during the application's own loading state, before the user starts using the next screen:
106
+
107
+ ```js
108
+ const appOpen = Admob.createAppOpen({
109
+ adUnitId: Admob.TEST_APP_OPEN,
110
+ autoReload: false
111
+ })
112
+
113
+ appOpen.addEventListener(Admob.AD_LOADED, () => {
114
+ Ti.API.info('App open ad is ready for the next foreground')
115
+ })
116
+
117
+ appOpen.load()
118
+ ```
119
+
120
+ ```js
121
+ function onForegroundLoadingScreen() {
122
+ if (appOpen.isLoaded()) {
123
+ appOpen.show()
124
+ } else {
125
+ appOpen.load()
126
+ }
127
+ }
128
+ ```
129
+
130
+ Call this only while your loading screen is visible and no consent form, other fullscreen ad or external flow is active. Do not wire an unconditional show to every activity resume: closing an ad or returning from its click can also resume the host. If loading finishes before the ad is ready, continue into the app and save the ad for a later opportunity. Remove any application lifecycle listener when its owner is disposed.
131
+
132
+ ### The four hour window
133
+
134
+ Google documents a four-hour validity window and its sample checks the time since the ad loaded. Both module proxies record successful load completion and check that age, with no timer and no extra event. See Google's [Android](https://developers.google.com/admob/android/app-open#consider_ad_expiration) and [iOS](https://developers.google.com/admob/ios/app-open) guides:
135
+
136
+ - The load time is recorded when the ad arrives.
137
+ - `isLoaded()` returns `false` once four hours have passed.
138
+ - `show()` on an expired ad clears the native reference and emits `failed_to_show` with code `1` and the message `App open ad expired after four hours`.
139
+ - `load()` discards an expired ad before requesting a new one, so a reload after expiry is not swallowed by the duplicate-load guard.
140
+
141
+ `autoReload` reloads only after `closed`. The application decides when to replace an expired ad. Expiry checks subtract the stored time when called; they do not poll in the background.
142
+
143
+ ## Creation properties
144
+
145
+ All four factories accept:
146
+
147
+ | Property | Type | Default | Notes |
148
+ | -------------- | -------- | ------- | ------------------------------------------------------------------ |
149
+ | `adUnitId` | String | `""` | Required before `load()`. |
150
+ | `autoReload` | Boolean | `false` | Loads a fresh ad after a successful close, and after nothing else. |
151
+ | `keywords` | String[] | None | Request keywords, applied as targeting on both platforms. |
152
+ | `requestAgent` | String | None | Identifies what issued the request, on both platforms. |
153
+ | `extras` | Object | None | Forwarded through Google ad-network extras on both platforms. |
154
+
155
+ Do not use `extras` to bypass UMP or synthesize personalization state.
156
+
157
+ Both platforms preserve primitive values in `extras`. Use the types required by the receiving adapter; for example, pass `{ npa: '1' }` when it expects a string.
158
+
159
+ Pass initial configuration to the factory. Later assignments to `adUnitId`, `keywords`, `requestAgent` and `extras` affect the next request on both platforms; an already loaded ad keeps its original request configuration. `autoReload` is a live close policy: both native ports read its current value when the shown ad closes, so changing it while an ad is loaded or presented changes whether that close starts another load. It does not present another ad or retry a load/show failure.
160
+
161
+ ## Shared methods
162
+
163
+ | Method | Description |
164
+ | ------------ | --------------------------------------------------------------------------------------------------------------- |
165
+ | `load()` | Starts one request. Calls while loading, loaded, or showing are ignored. App open discards an expired ad first. |
166
+ | `show()` | Presents the loaded ad or emits `failed_to_show`. |
167
+ | `isLoaded()` | Returns `true` only while an unused ad is ready. For app open, an ad older than four hours is not ready. |
168
+ | `destroy()` | Terminal, idempotent cleanup; emits `destroyed` once. |
169
+
170
+ Google fullscreen ads are single-use. Once presentation starts, `isLoaded()` is `false`. Native dismissal or presentation-failure callbacks discard the consumed reference. A local precondition failure, such as a missing host before presentation, can retain the unused ad; recheck readiness after correcting the condition. Call `load()` again before the next `show()`.
171
+
172
+ Late native callbacks are ignored after `destroy()`. A dismissed or failed-to-show ad reference is cleared before the terminal event is emitted.
173
+
174
+ On both platforms, `load()` after `destroy()` logs a warning without emitting an event. Banners emit `failed_to_load` in this case, so a handler must account for the proxy type.
175
+
176
+ On Android, `load()` and `show()` need a current activity, and without one they emit `failed_to_load` or `failed_to_show` with the message `No current activity available` and code `-1`. It happens when the application calls in with no activity in the foreground. Code `-1` is the module's own, outside Google's error-code range.
177
+
178
+ ## Keeping the next ad ready
179
+
180
+ For repeated presentations in one session, load the next ad after the previous one closes so it can be ready at the next break:
181
+
182
+ ```js
183
+ interstitial.addEventListener(Admob.AD_CLOSED, () => {
184
+ interstitial.load()
185
+ })
186
+ ```
187
+
188
+ `autoReload: true` reloads after `closed` only. The application handles retries after `failed_to_load` and `failed_to_show`. Use backoff: a `NO_FILL` response will often still be `NO_FILL` a second later.
189
+
190
+ Reuse the proxy across loads. Create a new one only after `destroy()`.
191
+
192
+ ## Events
193
+
194
+ ### Common events
195
+
196
+ | Event | Interstitial | Rewarded | App open | Rewarded interstitial | Common payload |
197
+ | --------------------------- | -----------: | -------: | -------: | -------: | -------------------------------------------------- |
198
+ | `loaded` | Yes | Yes | Yes | Yes | `adUnitId`, `adType` |
199
+ | `failed_to_load` | Yes | Yes | Yes | Yes | `adUnitId`, `adType`, `error`, `message`, `code` |
200
+ | `opened` | Yes | Yes | Yes | Yes | `adUnitId`, `adType` |
201
+ | `showed_fullscreen_content` | Yes | Yes | Yes | Yes | `adUnitId`, `adType` |
202
+ | `closed` | Yes | Yes | Yes | Yes | `adUnitId`, `adType` |
203
+ | `clicked` | Yes | Yes | Yes | Yes | `adUnitId`, `adType` |
204
+ | `impression` | Yes | Yes | Yes | Yes | `adUnitId`, `adType` |
205
+ | `failed_to_show` | Yes | Yes | Yes | Yes | `adUnitId`, `adType`, `error`, `message`, `code` |
206
+ | `destroyed` | Yes | Yes | Yes | Yes | `adUnitId`, `adType` |
207
+ | `rewarded` | No | Yes | No | Yes | `adUnitId`, `adType`, `rewardType`, `rewardAmount` |
208
+
209
+ `message` duplicates `error` for compatibility. New code may use `error`; both keys are portable.
210
+
211
+ ## iPad collapsed-SVG workaround
212
+
213
+ With the pinned GMA iOS 13.11.0 SDK, an Interstitial image creative can contain an SVG whose automatic width collapses in WebKit on iPad. The wrapper checks the presented Google WebView during a bounded first-second window. It repairs only `svg.advertiser-provided-image` with zero width, positive height, a valid SVG viewBox, a Google `simgad` background image and a column-flex parent. The parent receives the viewBox aspect ratio; visible images, intentionally hidden content and other layouts remain unchanged. Pending attempts stop on dismissal, presentation failure or destruction.
214
+
215
+ The check applies to Interstitials on iPad with both demo and publisher-owned unit IDs. It uses internal creative markup and is not an official Google SDK setting. Other templates, nested content or later layout failures may remain outside its scope. Rewarded and Rewarded Interstitial are not modified. Device tests established the original repair with Google's demo creative; extending eligibility to publisher IDs does not certify every production creative. Validate your units with [test devices enabled](https://developers.google.com/admob/ios/test-ads).
216
+
217
+ ## Cleanup
218
+
219
+ Use named callbacks and remove them before disposing the proxy:
220
+
221
+ ```js
222
+ function disposeInterstitial() {
223
+ interstitial.removeEventListener(Admob.AD_LOADED, onLoaded)
224
+ interstitial.removeEventListener(Admob.AD_FAILED_TO_LOAD, onFailed)
225
+ interstitial.removeEventListener(Admob.AD_CLOSED, onClosed)
226
+ interstitial.destroy()
227
+ }
228
+ ```
229
+
230
+ Create a new proxy after disposal; a destroyed proxy cannot load again.
231
+
232
+ ## Not implemented
233
+
234
+ The module exports format-name and test-ID constants for future compatibility, but it does not expose working factories for:
235
+
236
+ - Native
237
+
238
+ `TEST_NATIVE` names a unit no factory accepts.
@@ -0,0 +1,148 @@
1
+ # Game monetization and module integration
2
+
3
+ Use [fullscreen.md](fullscreen.md), [privacy.md](privacy.md) and
4
+ [library.md](library.md) for calls. This reference adds game-specific product
5
+ and lifecycle criteria, not a second module API. Reviewed against
6
+ `ti.admob.unified@034843299b2984253988e0ffccb9f6a1c91682c9` (1.0.0).
7
+ Read [production.md](production.md) before shipping an application. When
8
+ available, `ti-game-assets/references/responsible-ads.md` adds asset/game
9
+ coordination; this skill remains usable independently of it.
10
+
11
+ ## Current formats and their boundaries
12
+
13
+ | Placement | Integration boundary |
14
+ | --- | --- |
15
+ | Interstitial | Preload; show at a natural break without offering a reward. Avoid app entry, exit, active gameplay and repeated/consecutive interruptions. |
16
+ | Rewarded | Offer a clear voluntary exchange; present after acceptance; grant only from `rewarded` / `onRewarded`. |
17
+ | Rewarded interstitial | Implemented by `createRewardedInterstitial()` and its library manager. At a natural transition, explain the configured reward and show a clear, unobstructed Skip option before presentation, with enough time to understand and decline. The proxy/manager does not build this introduction. See [rewarded-interstitial.md](rewarded-interstitial.md). |
18
+ | App open | Implemented, but belongs only to an application's own foreground loading experience. Skip when content is already usable; do not show unconditionally from every resume. An expired ad needs a new load. |
19
+ | Banner/adaptive banner | Reserve a safe, measured slot away from controls; preserve that slot across ordinary screen pauses. See [banners.md](banners.md). |
20
+ | Native | No factory in 1.0.0. Format/test-ID constants alone do not implement it. |
21
+
22
+ Adding another implemented format still requires an intentional product decision.
23
+ Do not add forced rewarded continues or replace every retry with an ad. For a
24
+ rewarded-interstitial introduction, use the reward configured for that unit;
25
+ there is no pre-presentation reward getter. A visible Watch/Skip AlertDialog
26
+ works on both platforms; an iPad OptionDialog's hidden cancel item is not an
27
+ equivalent visible Skip action. Cancel a pending introduction when its screen
28
+ closes, the foreground or eligibility is lost, or another fullscreen is chosen.
29
+
30
+ Only the SDK's `rewarded` event grants value; `closed`, `impression`, clicks
31
+ and a successful Show attempt do not. The rewarded-interstitial native proxies
32
+ deduplicate reward callbacks per presentation and preserve the presented unit's
33
+ SDK reward while another request may load. Keep reward handling alive for the
34
+ SDK result: mediated reward and dismissal callback ordering can differ.
35
+ `destroy()` is terminal and suppresses late callbacks; it is not a dismissal API.
36
+ Client-side rewards do not provide server-side verification in this release.
37
+
38
+ ## Privacy and integration ownership
39
+
40
+ Run the consent-first flow on every app launch: register listeners, request
41
+ UMP, wait for `consent_complete`, evaluate `canRequestAds()`, initialize, then
42
+ load. A failed UMP update may retain permission from a previous choice; an
43
+ error alone is neither approval nor denial. Continue the game without ads
44
+ when unavailable. Raw fullscreen proxies do not enforce this gate.
45
+
46
+ ATT is separate. If the app uses it, resolve the foreground prompt after UMP
47
+ and before initialization; keep the required description/translations even if
48
+ an AdMob UMP IDFA message presents ATT. Query
49
+ `getTrackingAuthorizationStatus()` to inspect state without prompting, including
50
+ after Settings. Android's `applicable: false` / `authorized: true` convention
51
+ is not general tracking permission. ATT denial does not override UMP's request
52
+ gate. If explicitly requesting ATT, wait for `tracking_authorization_completed`
53
+ even when permission was resolved in an earlier session. See [privacy.md](privacy.md).
54
+
55
+ The copy-ready library owns sequencing, deferred loads, dimensions and placement
56
+ cleanup. It does **not** choose game breaks, impose frequency limits, pause
57
+ native gameplay/audio/input, or serialize unrelated application modal flows.
58
+ Its `start()` promise is cached even after an unavailable result; repeating it
59
+ is not a startup retry. Use the documented raw consent/init recovery flow if
60
+ recoverable startup is part of the application. Never reset production consent
61
+ to force another attempt.
62
+
63
+ Provide an interactive privacy action when required. Serialize it with ads,
64
+ ATT and Inspector; suspend new ad opportunities until its result is evaluated.
65
+ The library reauthorizes/replaces requests after dismissal. Raw consumers must
66
+ replace requests affected by changed choices themselves. Do not destroy an
67
+ onscreen fullscreen ad to dismiss it or treat `destroyAll()` as cancelling
68
+ UMP/Inspector: it releases placements only. See [library.md](library.md).
69
+
70
+ ## Community-Discovered Patterns
71
+
72
+ These are preserved author guidance and integration lessons from Lander/Guardian,
73
+ not additional module API or a verified optimal monetization policy. Their
74
+ frequency/director separation remains useful alongside the official library;
75
+ their application configuration and numeric thresholds are not defaults for
76
+ other games.
77
+
78
+ Choose deliberate natural breaks, such as settled end-of-run results, rather
79
+ than interrupting flight/combat or attaching an ad to every retry. Preserve
80
+ pause/tutorial/practice and voluntary-exit choices. Load early, but let the
81
+ application choose Show. A time threshold makes a later break eligible; it
82
+ never authorizes a timer-driven interruption. Google's
83
+ [interstitial placement guidance](https://support.google.com/admob/answer/6201362?hl=en)
84
+ disallows unexpected and excessive placements; re-check it before a live change.
85
+
86
+ Before presentation, capture the intended scene state, suspend native motion
87
+ and relevant timers, silence app-owned audio as appropriate, and release held
88
+ input. A stopped JS tick does not stop native gravity. Restore only the scene,
89
+ clock scale and audio that should still be active after dismissal or confirmed
90
+ failure, provided the owner is alive and the app is foregrounded. Do not blindly
91
+ resume a previously paused game, undo a newer navigation choice, or restore held
92
+ throttle/fire inputs. Returning from an ad is a lifecycle event, not a new ad
93
+ opportunity.
94
+
95
+ One application director owns presentation and rejects simultaneous attempts,
96
+ including UMP, ATT, Inspector and other fullscreen formats. Keep a once-only
97
+ continuation and an ownership/generation token so callbacks from an abandoned
98
+ screen cannot advance its successor. A missing-opening watchdog may recover an
99
+ attempt that never opens; after a confirmed `opened`, clear that watchdog and
100
+ wait for actual dismissal or presentation failure. An opening/impression does
101
+ not prove the creative was visibly rendered. Associate completion with the
102
+ active attempt: a rejected duplicate Show is not proof that an already open
103
+ ad has ended.
104
+
105
+ Distinguish the APIs at the boundary: raw `load()` / `show()` return no success
106
+ value. Library-manager `show()` returns `false` when not ready or when the
107
+ size guard requests a replacement; continue without blocking. A `true` result
108
+ means presentation was attempted and may still fail through `onFailedToShow`.
109
+ Supply the owning window. The manager does not queue a future Show after
110
+ returning `false`; a late load or background/resume must not launch a missed
111
+ interstitial. An explicit user-requested pending flow, such as the published
112
+ rewarded-interstitial demo, needs its own cancellation and introduction state.
113
+
114
+ Keep grace period, active-play accumulation, cooldown after dismissal,
115
+ hourly/daily caps and permitted boundaries distinct. Count actual openings
116
+ once and close separately; do not count both `opened` and
117
+ `showed_fullscreen_content` as two exposures. Preserve persistence and
118
+ conservative handling of clock rollback. Caps are ceilings, not exposure
119
+ targets, and application eligibility is separate from AdMob's ad-unit cap.
120
+ Use backoff after load/show failures; `autoReload` requests a replacement after
121
+ `closed` only and never presents it automatically.
122
+
123
+ A banner host must stay away from touch controls and reserve the native loaded
124
+ height inside safe areas. Choose `collapseOnFailure: false` on a library banner
125
+ when retrying should preserve its slot. Use screen-level `pause()` / `resume()`
126
+ only when navigation hides it while the same host lifecycle remains active;
127
+ background/activity lifecycle is already native. Pausing preserves the creative,
128
+ visibility and geometry; no JS refresh timer or destroy/recreate loop is needed.
129
+ On Android, ignore `_closeFromActivityForcedToDestroy` for placement teardown:
130
+ that close can be activity recreation rather than a destroyed screen. Remove
131
+ named listeners and destroy placements on actual owner disposal. Preserve reward
132
+ listeners until their result; destruction must not resume an abandoned game.
133
+
134
+ ## Acceptance in the consuming game
135
+
136
+ Use test units and test devices. Exercise unavailable module, no fill,
137
+ load/show failures, repeated taps, late/duplicate callbacks, reward once,
138
+ Skip, real dismissal, background/resume, privacy changes, rotation between
139
+ load/introduction/Show, owner destruction and phone/tablet layouts on both
140
+ platforms. Check native clock, input and audio restoration on each path.
141
+
142
+ A source check, wrapper test, SDK opening or impression does not prove visible
143
+ creative rendering, provider delivery or acceptable game frequency. Record
144
+ physical visual acceptance separately. Where telemetry is authorized, measure
145
+ confirmed exposure per active-play minute, abandonment at boundaries and
146
+ retention/retries. Unit tests do not prove players enjoy the frequency.
147
+ Production units, app verification, app-ads.txt, provider setup and store/privacy
148
+ disclosures belong to [production.md](production.md), not game frequency logic.