├── .gitignore ├── img ├── icon128.png ├── promo_tile_440x280.png ├── screenshot_github.png ├── screenshot_original.png ├── screenshot_webstores.png └── icon.svg ├── manifest.json ├── LICENSE ├── README.md └── aiwarningforsteam.user.js /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | src/ 3 | -------------------------------------------------------------------------------- /img/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeeeew/aiwarningforsteam/HEAD/img/icon128.png -------------------------------------------------------------------------------- /img/promo_tile_440x280.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeeeew/aiwarningforsteam/HEAD/img/promo_tile_440x280.png -------------------------------------------------------------------------------- /img/screenshot_github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeeeew/aiwarningforsteam/HEAD/img/screenshot_github.png -------------------------------------------------------------------------------- /img/screenshot_original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeeeew/aiwarningforsteam/HEAD/img/screenshot_original.png -------------------------------------------------------------------------------- /img/screenshot_webstores.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeeeew/aiwarningforsteam/HEAD/img/screenshot_webstores.png -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "AI warning for Steam", 4 | "short_name": "AI warning", 5 | "description": "Show the AI Generated Content Disclosure on Steam store pages as a modal popup.", 6 | "homepage_url": "https://github.com/seeeeew/aiwarningforsteam", 7 | "icons": { 8 | "128": "img/icon128.png" 9 | }, 10 | "version": "1.0.1", 11 | "content_scripts": [ 12 | { 13 | "matches": [ 14 | "*://store.steampowered.com/app/*" 15 | ], 16 | "js": [ 17 | "aiwarningforsteam.user.js" 18 | ] 19 | } 20 | ], 21 | "browser_specific_settings": { 22 | "gecko": { 23 | "id": "{29428906-aec3-11f0-beb4-6f7e24e82795}", 24 | "data_collection_permissions": { 25 | "required": ["none"] 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 seeeeew 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /img/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 14 | 16 | AI 26 | 31 | AI 41 | 42 | 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AI warning for Steam 2 | 3 | Shows the _AI Generated Content Disclosure_ on Steam store pages as a modal popup. 4 | 5 | ![Screenshot of a popup showing an AI Generated Content Disclosure in the Steam store](img/screenshot_github.png) 6 | 7 | If a Steam store page contains an _AI Generated Content Disclosure_, this extension will display it as a modal popup, instead of just at the end of the page. Additionally, it will blur out the rest of the page until the popup is dismissed. 8 | 9 | ## Installation 10 | 11 | **AI warning for Steam** can be installed as a native browser extension for Firefox or Chrome, or as a userscript for any supported browser. All variants run the exact same code, so installation and updates are the only differences. 12 | 13 | ### Option 1: Install as a browser extension for Firefox or Chrome 14 | 15 | This is the easier option, but updates can sometimes be delayed, because Mozilla and Google need to approve them first. (Usually this shouldn't take more than a day.) Just follow the appropriate link for your browser and click the install button. 16 | - [Firefox Add-ons](https://addons.mozilla.org/firefox/addon/ai-warning-for-steam/) 17 | - [Chrome Web Store](https://chromewebstore.google.com/detail/ai-warning-for-steam/clegcobheppnnigaaeelfkeomjcngmnh) 18 | 19 | ### Option 2: Install as a userscript 20 | 21 | This option is slightly less straight-forward, if you've never used a userscript, but you get updates as soon as they're available. 22 | 1. If necessary, install a userscript manager for your browser, for example by following the instructions at [Greasy Fork](https://greasyfork.org/#home-step-1). 23 | 2. [Click here to install the userscript](https://github.com/seeeeew/aiwarningforsteam/raw/refs/heads/main/aiwarningforsteam.user.js) _or_ download [`aiwarningforsteam.user.js`](https://github.com/seeeeew/aiwarningforsteam/blob/main/aiwarningforsteam.user.js) to install it manually. 24 | 25 | ## Platform and Language Support 26 | 27 | The native browser extension should work in any up-to-date version of Firefox, Chrome, or any related browsers that can install extensions from the same sources, on any desktop OS. The Firefox version also works on mobile systems. 28 | 29 | The userscript should work in any up-to-date browser with userscript support on any desktop or mobile OS. 30 | 31 | The extension supports all languages officially supported by the Steam store, but the download/installation pages as well as metadata like the extension description are only available in English. 32 | 33 | ## Project Scope 34 | 35 | This extension's sole purpose is making the _AI Generated Content Disclosure_ impossible to miss on Steam store pages where it exists. Future updates might improve this functionality, but will not add unrelated features. 36 | -------------------------------------------------------------------------------- /aiwarningforsteam.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name AI warning for Steam 3 | // @namespace https://github.com/seeeeew/aiwarningforsteam 4 | // @version 1.0.1 5 | // @description Shows the AI Generated Content Disclosure on Steam store pages as a modal popup. 6 | // @author seeeeew 7 | // @homepage https://github.com/seeeeew/aiwarningforsteam 8 | // @match https://store.steampowered.com/app/* 9 | // @icon https://raw.githubusercontent.com/seeeeew/aiwarningforsteam/refs/heads/main/img/icon128.png 10 | // @grant none 11 | // @run-at document-end 12 | // @updateURL https://github.com/seeeeew/aiwarningforsteam/raw/refs/heads/main/aiwarningforsteam.user.js 13 | // @downloadURL https://github.com/seeeeew/aiwarningforsteam/raw/refs/heads/main/aiwarningforsteam.user.js 14 | // @supportURL https://github.com/seeeeew/aiwarningforsteam/issues 15 | // @license MIT 16 | // ==/UserScript== 17 | 18 | (function() { 19 | 20 | const msg = { 21 | aidisclosure: { 22 | schinese: "AI 生成内容披露", 23 | tchinese: "AI 生成內容聲明", 24 | japanese: "AI生成コンテンツの開示", 25 | koreana: "AI 생성 콘텐츠 사용 공개", 26 | thai: "การเปิดเผยข้อมูลเกี่ยวกับเนื้อหาที่สร้างด้วย AI", 27 | bulgarian: "Оповестяване за съдържание, генерирано от ИИ", 28 | czech: "Informace o obsahu vytvářeném AI", 29 | danish: "Meddelelse om AI-genereret indhold", 30 | german: "Offenlegung von KI-generierten Inhalten", 31 | english: "AI Generated Content Disclosure", 32 | spanish: "Información sobre contenido generado por IA", 33 | latam: "Información sobre contenido generado por IA", 34 | greek: "Γνωστοποίηση περιεχομένου που δημιουργήθηκε από τεχνητή νοημοσύνη (AI)", 35 | french: "Divulgation de contenu généré par IA", 36 | italian: "Divulgazione dei contenuti generati dall'IA", 37 | indonesian: "Pernyataan Konten Buatan AI", 38 | hungarian: "Nyilatkozat MI generálta tartalomról", 39 | dutch: "Informatie over door AI gegenereerde inhoud", 40 | norwegian: "Opplysning om AI-generert innhold", 41 | polish: "Oświadczenie w sprawie treści generowanych przez SI", 42 | portuguese: "Divulgação de conteúdo gerado por IA", 43 | brazilian: "Divulgação de conteúdo gerado por IA", 44 | romanian: "Informații despre conținutul generat de IA", 45 | russian: "Информация о контенте, созданном с помощью ИИ", 46 | finnish: "Tiedote tekoälysisällöstä", 47 | swedish: "Upplysning om AI-genererat innehåll", 48 | turkish: "Yapay Zekâ İçeriği Açıklaması", 49 | vietnamese: "Công bố về nội dung tạo bởi AI", 50 | ukrainian: "Розкриття інформації щодо вмісту, згенерованого ШІ", 51 | }, 52 | close: { 53 | schinese: "关闭", 54 | tchinese: "關閉", 55 | japanese: "閉じる", 56 | koreana: "닫기", 57 | thai: "ปิด", 58 | bulgarian: "Затваряне", 59 | czech: "Zavřít", 60 | danish: "Luk", 61 | german: "Schließen", 62 | english: "Close", 63 | spanish: "Cerrar", 64 | latam: "Cerrar", 65 | greek: "Κλείσιμο", 66 | french: "Fermer", 67 | italian: "Chiudi", 68 | indonesian: "Tutup", 69 | hungarian: "Bezárás", 70 | dutch: "Sluiten", 71 | norwegian: "Lukk", 72 | polish: "Zamknij", 73 | portuguese: "Fechar", 74 | brazilian: "Fechar", 75 | romanian: "Închide", 76 | russian: "Закрыть", 77 | finnish: "Sulje", 78 | swedish: "Stäng", 79 | turkish: "Kapat", 80 | vietnamese: "Đóng", 81 | ukrainian: "Закрити", 82 | } 83 | // Currently latam and brazilian aren't recognized and are only included 84 | // for completeness, but we can ignore that for now, because both their 85 | // strings are identical to spanish and portuguese respectively. 86 | } 87 | 88 | function findAIDisclosureHeader() { 89 | const titles = Object.values(msg.aidisclosure); 90 | return [...document.querySelectorAll(".game_page_autocollapse > #game_area_content_descriptors > h2")].find(element => titles.includes(element.textContent)); 91 | } 92 | 93 | function injectStyle() { 94 | const style = document.createElement("style"); 95 | style.innerHTML = ` 96 | .aiwarning_container { 97 | position: fixed; 98 | inset: 0px; 99 | backdrop-filter: blur(25px); 100 | z-index: 1999; /* cookie consent popup has 2000 */ 101 | background-color: rgba(0, 0, 0, 0.6); 102 | display: flex; 103 | justify-content: center; 104 | align-items: center; 105 | } 106 | .aiwarning_container .newmodal { 107 | box-shadow: 0px 0px 10px #000000; 108 | position: relative; 109 | } 110 | .aiwarning_container .title_text { 111 | margin-right: 20px; 112 | } 113 | .aiwarning_container .newmodal_content { 114 | max-height: 350px; 115 | } 116 | .aiwarning_watermark { 117 | position: absolute; 118 | left: 10px; 119 | bottom: 10px; 120 | color: white; 121 | opacity: 0.25; 122 | text-decoration: none; 123 | font-size: 12px; 124 | } 125 | .aiwarning_watermark:hover { 126 | opacity: 0.6; 127 | } 128 | `; 129 | document.head.append(style); 130 | return style; 131 | } 132 | 133 | function getMetadata() { 134 | const metadata = {}; 135 | if (typeof GM_info !== "undefined") { 136 | metadata.homepage = GM_info.script.homepage; 137 | metadata.name = GM_info.script.name; 138 | metadata.version = GM_info.script.version; 139 | } else if (typeof browser !== "undefined") { 140 | metadata.homepage = browser.runtime.getManifest().homepage_url; 141 | metadata.name = browser.runtime.getManifest().name; 142 | metadata.version = browser.runtime.getManifest().version; 143 | } else if (typeof chrome !== "undefined") { 144 | metadata.homepage = chrome.runtime.getManifest().homepage_url; 145 | metadata.name = chrome.runtime.getManifest().name; 146 | metadata.version = chrome.runtime.getManifest().version; 147 | } 148 | return metadata; 149 | } 150 | 151 | function findKeyForValue(object, value) { 152 | return Object.keys(object).find(key => object[key] === value); 153 | } 154 | 155 | function createWarning(header) { 156 | const style = injectStyle(); 157 | const {homepage, name, version} = getMetadata(); 158 | const language = findKeyForValue(msg.aidisclosure, header.textContent); 159 | const container = document.createElement("div"); 160 | container.classList.add("aiwarning_container"); 161 | const appname = document.querySelector("#appHubAppName")?.textContent; 162 | const title = header.innerHTML + (appname ? " — " + appname : ""); 163 | container.innerHTML = ` 164 |
165 | 166 |
167 |
168 |
169 |
${title}
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 | ${msg.close[language]} 178 |
179 |
180 |
181 |
182 | ${name} v${version} 183 |
184 | `; 185 | container.querySelector(".newmodal_prompt_description").append(...[...header.parentNode.childNodes].filter(node => node !== header).map(node => node.cloneNode(true))); 186 | function closeWarning() { 187 | container.remove(); 188 | style.remove(); 189 | } 190 | container.querySelectorAll(".newmodal_close, .aiwarning_close").forEach(element => element.addEventListener("click", closeWarning)); 191 | container.addEventListener("click", event => { 192 | if (event.target === container) closeWarning(); 193 | }); 194 | document.body.append(container); 195 | } 196 | 197 | const header = findAIDisclosureHeader(); 198 | const warning = document.querySelector(".aiwarning_container"); 199 | if (header && !warning) { 200 | createWarning(header); 201 | } 202 | 203 | })(); --------------------------------------------------------------------------------