From 73016bb56bcc2bc5b0df250e7e4ca06d7ad41e6d Mon Sep 17 00:00:00 2001 From: Evan Date: Fri, 27 Mar 2026 11:57:42 -0700 Subject: [PATCH] Add bottom left ad in crazygames (#3526) ## Description: If on crazy games, shows an in-game ad on the bottom left corner ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: evan --- src/client/CrazyGamesSDK.ts | 76 ++++++++++++++++++++++- src/client/graphics/layers/InGamePromo.ts | 40 +++++++++++- 2 files changed, 113 insertions(+), 3 deletions(-) diff --git a/src/client/CrazyGamesSDK.ts b/src/client/CrazyGamesSDK.ts index 1933074ec..ae2d5bf1d 100644 --- a/src/client/CrazyGamesSDK.ts +++ b/src/client/CrazyGamesSDK.ts @@ -25,6 +25,16 @@ declare global { }, ) => void; }; + banner: { + requestBanner: (options: { + id: string; + width: number; + height: number; + }) => Promise; + requestResponsiveBanner: (containerId: string) => Promise; + clearBanner: (containerId: string) => void; + clearAllBanners: () => void; + }; game: { gameplayStart: () => Promise; gameplayStop: () => Promise; @@ -76,11 +86,9 @@ export class CrazyGamesSDK { } return false; } catch (e) { - console.log("[CrazyGames]: ", e); // If we get a cross-origin error, we're definitely iframed // Check our own referrer as fallback const isCrazyGames = document.referrer.includes("crazygames"); - console.log("[CrazyGames], contains referrer: ", isCrazyGames); if (isCrazyGames) { return true; } @@ -323,6 +331,70 @@ export class CrazyGamesSDK { } } + private bottomLeftContainerId = "cg-bottom-left-ad"; + private bottomLeftAdVisible = false; + + createBottomLeftAd(): void { + console.log( + `[CrazyGames] createBottomLeftAd called, isReady=${this.isReady()}`, + ); + if (!this.isReady()) { + console.log("[CrazyGames] SDK not ready, skipping bottom-left ad"); + return; + } + + if (this.bottomLeftAdVisible) { + console.log("[CrazyGames] Bottom-left ad already visible"); + return; + } + + // Remove existing container if any + document.getElementById(this.bottomLeftContainerId)?.remove(); + + const container = document.createElement("div"); + container.id = this.bottomLeftContainerId; + container.style.cssText = ` + position: fixed; + bottom: 0; + left: 0; + width: 300px; + height: 250px; + z-index: 9999; + pointer-events: auto; + `; + document.body.appendChild(container); + console.log("[CrazyGames] Created bottom-left ad container"); + + (async () => { + try { + await window.CrazyGames!.SDK.banner.requestBanner({ + id: this.bottomLeftContainerId, + width: 300, + height: 250, + }); + console.log("[CrazyGames] Bottom-left banner loaded"); + } catch (e) { + console.log("[CrazyGames] Bottom-left banner error:", e); + } + })(); + + this.bottomLeftAdVisible = true; + } + + clearBottomLeftAd(): void { + if (!this.bottomLeftAdVisible) return; + + try { + window.CrazyGames!.SDK.banner.clearBanner(this.bottomLeftContainerId); + } catch (e) { + console.error("[CrazyGames] Error clearing bottom-left banner:", e); + } + + document.getElementById(this.bottomLeftContainerId)?.remove(); + this.bottomLeftAdVisible = false; + console.log("[CrazyGames] Bottom-left ad cleared"); + } + requestMidgameAd(): Promise { return new Promise((resolve) => { if (!this.isReady()) { diff --git a/src/client/graphics/layers/InGamePromo.ts b/src/client/graphics/layers/InGamePromo.ts index 097bf5bd6..b4d58e237 100644 --- a/src/client/graphics/layers/InGamePromo.ts +++ b/src/client/graphics/layers/InGamePromo.ts @@ -1,6 +1,7 @@ import { LitElement, html } from "lit"; import { customElement } from "lit/decorators.js"; import { GameView } from "../../../core/game/GameView"; +import { crazyGamesSDK } from "../../CrazyGamesSDK"; import { Layer } from "./Layer"; const AD_TYPE = "standard_iab_left1"; @@ -30,6 +31,7 @@ export class InGamePromo extends LitElement implements Layer { } if (!this.cornerAdShown) { this.cornerAdShown = true; + console.log("[InGamePromo] Spawn phase ended, triggering showAd"); this.showAd(); } } @@ -73,10 +75,19 @@ export class InGamePromo extends LitElement implements Layer { } private showAd(): void { - if (!window.adsEnabled) return; + console.log( + `[InGamePromo] showAd called, isOnCrazyGames=${crazyGamesSDK.isOnCrazyGames()}`, + ); if (window.innerWidth < 1100) return; if (window.innerHeight < 750) return; + if (crazyGamesSDK.isOnCrazyGames()) { + this.showCrazyGamesAd(); + return; + } + + if (!window.adsEnabled) return; + this.shouldShow = true; this.requestUpdate(); @@ -85,6 +96,25 @@ export class InGamePromo extends LitElement implements Layer { }); } + private showCrazyGamesAd(): void { + console.log( + `[InGamePromo] showCrazyGamesAd called, isReady=${crazyGamesSDK.isReady()}, width=${window.innerWidth}, height=${window.innerHeight}`, + ); + if (!crazyGamesSDK.isReady()) { + console.log( + "[InGamePromo] CrazyGames SDK not ready, skipping in-game ad", + ); + return; + } + + this.requestUpdate(); + + this.updateComplete.then(() => { + console.log("[InGamePromo] DOM updated, calling createBottomLeftAd"); + crazyGamesSDK.createBottomLeftAd(); + }); + } + private loadAd(): void { if (!window.ramp) { console.warn("Playwire RAMP not available for in-game ad"); @@ -112,6 +142,14 @@ export class InGamePromo extends LitElement implements Layer { public hideAd(): void { this.destroyBottomRail(); + + if (crazyGamesSDK.isOnCrazyGames()) { + crazyGamesSDK.clearBottomLeftAd(); + this.shouldShow = false; + this.requestUpdate(); + return; + } + if (!window.ramp) { console.warn("Playwire RAMP not available for in-game ad"); return;