From 51db6a2772490432297ceaef07e4a4288ecafaf7 Mon Sep 17 00:00:00 2001 From: Evan Date: Mon, 16 Mar 2026 19:36:02 -0700 Subject: [PATCH] Add in game add to bottom left corner (#3446) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description: Remove the header ad because that's where the player info overlay is, and instead put it on the bottom left Ad is not displayed on small screens. Screenshot 2026-03-16 at 7 27 58 PM ## 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 --- index.html | 2 +- src/client/graphics/GameRenderer.ts | 14 +-- src/client/graphics/layers/InGameHeaderAd.ts | 119 ------------------- src/client/graphics/layers/InGamePromo.ts | 93 +++++++++++++++ 4 files changed, 100 insertions(+), 128 deletions(-) delete mode 100644 src/client/graphics/layers/InGameHeaderAd.ts create mode 100644 src/client/graphics/layers/InGamePromo.ts diff --git a/index.html b/index.html index ab3609a02..46eca8f14 100644 --- a/index.html +++ b/index.html @@ -319,7 +319,7 @@ - + diff --git a/src/client/graphics/GameRenderer.ts b/src/client/graphics/GameRenderer.ts index 8956214d6..fb0c96810 100644 --- a/src/client/graphics/GameRenderer.ts +++ b/src/client/graphics/GameRenderer.ts @@ -21,7 +21,7 @@ import { GameLeftSidebar } from "./layers/GameLeftSidebar"; import { GameRightSidebar } from "./layers/GameRightSidebar"; import { HeadsUpMessage } from "./layers/HeadsUpMessage"; import { ImmunityTimer } from "./layers/ImmunityTimer"; -import { InGameHeaderAd } from "./layers/InGameHeaderAd"; +import { InGamePromo } from "./layers/InGamePromo"; import { Layer } from "./layers/Layer"; import { Leaderboard } from "./layers/Leaderboard"; import { MainRadialMenu } from "./layers/MainRadialMenu"; @@ -262,13 +262,11 @@ export function createRenderer( immunityTimer.game = game; immunityTimer.eventBus = eventBus; - const inGameHeaderAd = document.querySelector( - "in-game-header-ad", - ) as InGameHeaderAd; - if (!(inGameHeaderAd instanceof InGameHeaderAd)) { - console.error("in-game header ad not found"); + const inGamePromo = document.querySelector("in-game-promo") as InGamePromo; + if (!(inGamePromo instanceof InGamePromo)) { + console.error("in-game promo not found"); } - inGameHeaderAd.game = game; + inGamePromo.game = game; const spawnVideoAd = document.querySelector("spawn-video-ad") as SpawnVideoAd; if (!(spawnVideoAd instanceof SpawnVideoAd)) { @@ -321,7 +319,7 @@ export function createRenderer( playerPanel, headsUpMessage, multiTabModal, - inGameHeaderAd, + inGamePromo, spawnVideoAd, alertFrame, performanceOverlay, diff --git a/src/client/graphics/layers/InGameHeaderAd.ts b/src/client/graphics/layers/InGameHeaderAd.ts deleted file mode 100644 index 52585cdba..000000000 --- a/src/client/graphics/layers/InGameHeaderAd.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { LitElement, html } from "lit"; -import { customElement } from "lit/decorators.js"; -import { GameView } from "../../../core/game/GameView"; -import { Layer } from "./Layer"; - -const AD_SHOW_TICKS = 10 * 60 * 10; // 2 minutes -const HEADER_AD_TYPE = "standard_iab_head1"; -const HEADER_AD_CONTAINER_ID = "header-ad-container"; -const TWO_XL_BREAKPOINT = 1536; - -@customElement("in-game-header-ad") -export class InGameHeaderAd extends LitElement implements Layer { - public game: GameView; - - private isHidden: boolean = false; - private adLoaded: boolean = false; - private shouldShow: boolean = false; - - createRenderRoot() { - return this; - } - - init() { - // TODO: move ad and re-enable. - // this.showHeaderAd(); - } - - private showHeaderAd(): void { - // Don't show header ad on screens smaller than 2xl - if (window.innerWidth < TWO_XL_BREAKPOINT) { - return; - } - if (!window.adsEnabled) { - return; - } - - this.shouldShow = true; - this.requestUpdate(); - - // Wait for the element to render before loading the ad - this.updateComplete.then(() => { - this.loadAd(); - }); - } - - private loadAd(): void { - if (!window.ramp) { - console.warn("Playwire RAMP not available for header ad"); - return; - } - - try { - window.ramp.que.push(() => { - try { - window.ramp.spaAddAds([ - { - type: HEADER_AD_TYPE, - selectorId: HEADER_AD_CONTAINER_ID, - }, - ]); - this.adLoaded = true; - console.log("Header ad loaded:", HEADER_AD_TYPE); - } catch (e) { - console.error("Failed to add header ad:", e); - } - }); - } catch (error) { - console.error("Failed to load header ad:", error); - } - } - - private hideHeaderAd(): void { - this.shouldShow = false; - this.adLoaded = false; - try { - window.ramp.destroyUnits(HEADER_AD_TYPE); - console.log("successfully destroyed in game header ad"); - } catch (e) { - console.error("error destroying in game header ad", e); - } - this.requestUpdate(); - } - - public tick() { - if (this.isHidden) { - return; - } - - const gameTicks = - this.game.ticks() - this.game.config().numSpawnPhaseTurns(); - if (gameTicks > AD_SHOW_TICKS) { - console.log("destroying header ad and refreshing PageOS"); - this.hideHeaderAd(); - this.isHidden = true; - - if (window.PageOS?.session?.newPageView) { - window.PageOS.session.newPageView(); - } - return; - } - } - - shouldTransform(): boolean { - return false; - } - - render() { - if (!this.shouldShow) { - return html``; - } - - return html` - - `; - } -} diff --git a/src/client/graphics/layers/InGamePromo.ts b/src/client/graphics/layers/InGamePromo.ts new file mode 100644 index 000000000..a160e5924 --- /dev/null +++ b/src/client/graphics/layers/InGamePromo.ts @@ -0,0 +1,93 @@ +import { LitElement, html } from "lit"; +import { customElement } from "lit/decorators.js"; +import { GameView } from "../../../core/game/GameView"; +import { Layer } from "./Layer"; + +const AD_TYPE = "standard_iab_left1"; +const AD_CONTAINER_ID = "in-game-bottom-left-ad"; + +@customElement("in-game-promo") +export class InGamePromo extends LitElement implements Layer { + public game: GameView; + + private shouldShow: boolean = false; + + createRenderRoot() { + return this; + } + + init() { + this.showAd(); + } + + private showAd(): void { + if (!window.adsEnabled) return; + if (window.innerWidth < 1100) return; + if (window.innerHeight < 750) return; + + this.shouldShow = true; + this.requestUpdate(); + + this.updateComplete.then(() => { + this.loadAd(); + }); + } + + private loadAd(): void { + if (!window.ramp) { + console.warn("Playwire RAMP not available for in-game ad"); + return; + } + + try { + window.ramp.que.push(() => { + try { + window.ramp.spaAddAds([ + { + type: AD_TYPE, + selectorId: AD_CONTAINER_ID, + }, + ]); + console.log("In-game bottom-left ad loaded:", AD_TYPE); + } catch (e) { + console.error("Failed to add in-game ad:", e); + } + }); + } catch (error) { + console.error("Failed to load in-game ad:", error); + } + } + + public hideAd(): void { + if (!window.ramp) { + console.warn("Playwire RAMP not available for in-game ad"); + return; + } + this.shouldShow = false; + try { + window.ramp.destroyUnits(AD_TYPE); + console.log("successfully destroyed in-game bottom-left ad"); + } catch (e) { + console.error("error destroying in-game ad:", e); + } + this.requestUpdate(); + } + + shouldTransform(): boolean { + return false; + } + + render() { + if (!this.shouldShow) { + return html``; + } + + return html` +
+ `; + } +}