diff --git a/css/art/genAI.css b/css/art/genAI.css
index c13b959d1b2e617510b2d836490e56a132c55734..a0d86a67104420a4767406fcf205bf7e89e01d36 100644
--- a/css/art/genAI.css
+++ b/css/art/genAI.css
@@ -49,7 +49,7 @@
     transition: opacity 300ms ease-in-out;
 }
 
-.spinner {
+.ai-spinner {
     display: none;
     position: absolute;
     top: 50%;
@@ -83,7 +83,7 @@
     object-fit: contain;
 }
 
-.ai-art-container.refreshing .spinner {
+.ai-art-container.refreshing .ai-spinner {
     display: block;
 }
 
@@ -164,3 +164,44 @@
         transform: translate(-50%, -50%) rotate(360deg);
     }
 }
+
+.ai-queue-overlay {
+    position: fixed;
+    right: 0;
+    bottom: 0;
+    background-color: #1a1a1a;
+    border-left: #333 2px solid;
+    border-top: #333 2px solid;
+    border-top-left-radius: 1em;
+    padding: 0.5em;
+
+}
+
+.ai-queue-overlay.hidden {
+    display: none;
+}
+
+.ai-queue-overlay .spinner {
+    display: inline-block;
+    width: 2.3em;
+}
+
+.ai-queue-overlay .spinner::after {
+    font-family: 'sc-icons';
+    content: "\f110";
+    position: absolute;
+    top: 50%;
+    left: 0.9em;
+    font-size: 25px;
+    animation: spin 3s linear infinite;
+}
+
+.ai-queue-overlay button {
+    font-family: 'sc-icons';
+    background-color: var(--button-color);
+    border: solid 2px var(--button-border-color);
+}
+
+.ai-queue-overlay button:hover {
+    background-color: var(--button-hover-color);
+}
diff --git a/js/003-data/gameVariableData.js b/js/003-data/gameVariableData.js
index 6b703ed3408f80050100e33bcaf35547f4a40a05..fe7bb6eda1451d71806b1f5ada029819b741f4c2 100644
--- a/js/003-data/gameVariableData.js
+++ b/js/003-data/gameVariableData.js
@@ -285,6 +285,7 @@ App.Data.defaultGameStateVariables = {
 	aiApiUrl: "http://localhost:7860",
 	aiAutoGen: true,
 	aiAutoGenFrequency: 10,
+	aiQueueOverlay: 1,
 	aiUseRAForEvents: false,
 	aiCfgScale: 5,
 	aiTimeoutPerStep: 5,
diff --git a/src/art/artJS.js b/src/art/artJS.js
index 63c20dfde2f39a3ba44467322bf3b02b0d003ffa..d013dbc40c2e8d75f159aef9ce5ceb4bd4abd498 100644
--- a/src/art/artJS.js
+++ b/src/art/artJS.js
@@ -599,7 +599,7 @@ App.Art.aiArtElement = function(slave, imageSize, isEventImage = null) {
 
 	// Loading spinner
 	// eslint-disable-next-line no-unused-vars
-	spinner = App.UI.DOM.appendNewElement('div', container, '⟳', ['spinner']);
+	spinner = App.UI.DOM.appendNewElement('div', container, '⟳', ['ai-spinner']);
 
 
 	const reactiveSpecific = {
diff --git a/src/art/genAI/queueOverlay.js b/src/art/genAI/queueOverlay.js
new file mode 100644
index 0000000000000000000000000000000000000000..2c04267a164441b43f73c1003cb51c084c05ecb3
--- /dev/null
+++ b/src/art/genAI/queueOverlay.js
@@ -0,0 +1,61 @@
+App.Art.GenAI.UI.QueueOverlay = function() {
+	// Internal State
+	let toggleVisible = true;
+	let generating = false;
+
+	// Setup containers
+	const container = document.createElement("div");
+	container.classList.add("ai-queue-overlay");
+	document.body.append(container);
+
+	const mainQueueSpan = document.createElement("span");
+	const backlogSpan = document.createElement("span");
+
+
+	// Export functionality
+	return {init: init, toggle: toggle};
+
+	function init() {
+		// Setup content
+		const spinnerSpan = document.createElement("span");
+		spinnerSpan.classList.add("spinner");
+		container.append(spinnerSpan);
+
+		container.append("(Queue: ", mainQueueSpan, " / Backlog: ", backlogSpan, ") ");
+
+		const button = document.createElement("button");
+		button.append("\uf410");
+		button.onclick = () => App.Art.GenAI.sdQueue.interrupt();
+		container.append(button);
+
+		// Callback
+		App.Art.GenAI.sdQueue.registerStatusChangeCallback(queueChangeCallback);
+	}
+
+	/**
+	 * @param {ArtQueueState} status
+	 */
+	function queueChangeCallback(status) {
+		mainQueueSpan.textContent = String(status.mainQueueCount);
+		backlogSpan.textContent = String(status.backlogCount);
+		generating = status.active;
+		updateVisible();
+	}
+
+	/**
+	 * @param {boolean} visible
+	 */
+	function toggle(visible) {
+		toggleVisible = visible;
+		updateVisible();
+	}
+
+	function updateVisible() {
+		const visible = V.aiQueueOverlay === 1 && toggleVisible && generating;
+		if (visible) {
+			container.classList.remove("hidden");
+		} else {
+			container.classList.add("hidden");
+		}
+	}
+}();
diff --git a/src/art/genAI/stableDiffusion.js b/src/art/genAI/stableDiffusion.js
index a9bc7e0a03cd608ca181c601a2ba103e0f5ede9b..8bdddef1f3e3b6756e6a871f48559400b9e366ab 100644
--- a/src/art/genAI/stableDiffusion.js
+++ b/src/art/genAI/stableDiffusion.js
@@ -111,6 +111,13 @@ async function fetchWithTimeout(url, timeout, options) {
  * @property {[function(string): void]} rejects
  */
 
+/**
+ * @typedef {object} ArtQueueState
+ * @property {boolean} active
+ * @property {number} mainQueueCount
+ * @property {number} backlogCount
+ */
+
 App.Art.GenAI.StableDiffusionClientQueue = class {
 	constructor() {
 		// Images for this current screen
@@ -124,6 +131,11 @@ App.Art.GenAI.StableDiffusionClientQueue = class {
 		this.workingOnID = null;
 		/** @type {string|null} */
 		this.workingOnBody = null;
+		/**
+		 * @type {Array<function(ArtQueueState): void>}
+		 * @private
+		 */
+		this._statusChangeCallbacks = [];
 	}
 
 	resetWorkingOnProperties() {
@@ -131,6 +143,15 @@ App.Art.GenAI.StableDiffusionClientQueue = class {
 		this.workingOnID = null;
 	}
 
+	/**
+	 * First value is main queue, second backlog queue
+	 *
+	 * @param {function(ArtQueueState): void} callback
+	 */
+	registerStatusChangeCallback(callback) {
+		this._statusChangeCallbacks.push(callback);
+	}
+
 	/**
 	 * Updates the queue counts if on the ai image settings page
 	 */
@@ -148,6 +169,14 @@ App.Art.GenAI.StableDiffusionClientQueue = class {
 				queue.empty().append(count.toString());
 			}
 		});
+		const state = {
+			active: this.workingOnID !== null,
+			mainQueueCount: this.queue.length,
+			backlogCount: this.backlogQueue.length
+		};
+		for (const callback of this._statusChangeCallbacks) {
+			callback(state);
+		}
 	}
 
 	openWebSocket(top, options) {
diff --git a/src/art/genAI/uiOptions.js b/src/art/genAI/uiOptions.js
index 243096e7e6750aaea19a1066bfa151991c911ae5..2c21230c04ae1bbf57e235fd9d283fe6b92ec3ce 100644
--- a/src/art/genAI/uiOptions.js
+++ b/src/art/genAI/uiOptions.js
@@ -976,6 +976,9 @@ App.Art.GenAI.UI.Options.aiGenerationSettings = () => {
 		}
 	}
 
+	options.addOption("Generation Queue Overlay", "aiQueueOverlay")
+		.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
 	el.append(options.render());
 	return el;
 };
diff --git a/src/zz1-last/init.js b/src/zz1-last/init.js
index 0bc001dd5bc5ceccf9d46740e236ac54d3a1cae7..2a3926cae3af44b8615213846ea8558b2c2feafd 100644
--- a/src/zz1-last/init.js
+++ b/src/zz1-last/init.js
@@ -1,3 +1,4 @@
 App.Art.cacheArtData();
 App.Corporate.Init();
 App.RA.Activation.populateGetters();
+App.Art.GenAI.UI.QueueOverlay.init();
diff --git a/src/zz1-last/setupEventHandlers.js b/src/zz1-last/setupEventHandlers.js
index cdf7277ca7d03566503f8d020d6163178510fc0d..e34f07aaf7a86e30f37636a0f40bcc9b7cb67307 100644
--- a/src/zz1-last/setupEventHandlers.js
+++ b/src/zz1-last/setupEventHandlers.js
@@ -22,6 +22,7 @@ $(document).on(":passagestart", event => {
 		enumerable: true
 	});
 	App?.Utils?.passageHistoryCleanup();
+	App.Art.GenAI.UI.QueueOverlay.toggle(passage() !== "Options");
 	profileEvents.passagestart();
 });