diff --git a/extensions/Twingamerdudes/modals.js b/extensions/Twingamerdudes/modals.js
new file mode 100644
index 0000000000..66f41d1ee2
--- /dev/null
+++ b/extensions/Twingamerdudes/modals.js
@@ -0,0 +1,415 @@
+// Name: Modals
+// ID: modals
+// Description: Adds support for HTML modals.
+// By: Twingamerdudes
+(function (Scratch) {
+ "use strict";
+
+ if (!Scratch.extensions.unsandboxed) {
+ throw new Error("Modals must run unsandboxed");
+ }
+
+ const vm = Scratch.vm;
+ let modalInput = ""; // By: Twingamerdudes
+ // Original: YourMom
+ let buttonPressed = "";
+ let isModalOpen = false;
+ class Modals {
+ getInfo() {
+ return {
+ id: "modals",
+ name: "Modals",
+ color1: "#a01c1c",
+ color2: "#861515",
+ color3: "#6d1212",
+ blocks: [
+ {
+ opcode: "showModal",
+ blockType: Scratch.BlockType.COMMAND,
+ text: "show modal [TEXT] with the background [COLOR] and text color [TCOLOR]",
+ arguments: {
+ TEXT: {
+ type: Scratch.ArgumentType.STRING,
+ defaultValue: "Hello World!",
+ },
+ COLOR: {
+ type: Scratch.ArgumentType.COLOR,
+ defaultValue: "#696969",
+ },
+ TCOLOR: {
+ type: Scratch.ArgumentType.COLOR,
+ defaultValue: "#ffffff",
+ },
+ },
+ },
+ {
+ opcode: "showModalWithInput",
+ blockType: Scratch.BlockType.COMMAND,
+ text: "show input modal [TEXT] with the background [COLOR] secondary color [SCOLOR], text color [TCOLOR], and placeholder [PLACEHOLDER]",
+ arguments: {
+ TEXT: {
+ type: Scratch.ArgumentType.STRING,
+ defaultValue: "Hello World!",
+ },
+ COLOR: {
+ type: Scratch.ArgumentType.COLOR,
+ defaultValue: "#696969",
+ },
+ TCOLOR: {
+ type: Scratch.ArgumentType.COLOR,
+ defaultValue: "#ffffff",
+ },
+ SCOLOR: {
+ type: Scratch.ArgumentType.COLOR,
+ defaultValue: "#808080",
+ },
+ PLACEHOLDER: {
+ type: Scratch.ArgumentType.STRING,
+ defaultValue: "Your text.",
+ },
+ },
+ },
+ {
+ opcode: "closeModal",
+ blockType: Scratch.BlockType.COMMAND,
+ text: "close modal",
+ },
+ {
+ opcode: "addTextToModal",
+ blockType: Scratch.BlockType.COMMAND,
+ text: "add [TEXT] to the current modal",
+ arguments: {
+ TEXT: {
+ type: Scratch.ArgumentType.STRING,
+ defaultValue: "Hello World!",
+ },
+ },
+ },
+ {
+ opcode: "addModalButton",
+ blockType: Scratch.BlockType.COMMAND,
+ text: "add button [NAME] with the background color of [SCOLOR] and the text color of [TCOLOR] to the current modal",
+ arguments: {
+ NAME: {
+ type: Scratch.ArgumentType.STRING,
+ defaultValue: "My Button",
+ },
+ SCOLOR: {
+ type: Scratch.ArgumentType.COLOR,
+ defaultValue: "#808080",
+ },
+ TCOLOR: {
+ type: Scratch.ArgumentType.COLOR,
+ defaultValue: "#ffffff",
+ },
+ },
+ },
+ {
+ opcode: "changeDefaultModalText",
+ blockType: Scratch.BlockType.COMMAND,
+ text: "change default modal text to [TEXT]",
+ arguments: {
+ TEXT: {
+ type: Scratch.ArgumentType.STRING,
+ defaultValue: "Hello World!",
+ },
+ },
+ },
+ {
+ opcode: "changeDefaultModalColor",
+ blockType: Scratch.BlockType.COMMAND,
+ text: "change modal background color to [COLOR]",
+ arguments: {
+ COLOR: {
+ type: Scratch.ArgumentType.COLOR,
+ defaultValue: "#696969",
+ },
+ },
+ },
+ {
+ opcode: "changeDefaultModalTextColor",
+ blockType: Scratch.BlockType.COMMAND,
+ text: "change modal text color to [COLOR]",
+ arguments: {
+ COLOR: {
+ type: Scratch.ArgumentType.COLOR,
+ defaultValue: "#ffffff",
+ },
+ },
+ },
+ {
+ opcode: "inputModalValue",
+ blockType: Scratch.BlockType.REPORTER,
+ text: "input modal value",
+ disableMonitor: true,
+ },
+ {
+ opcode: "IsModalOpen",
+ blockType: Scratch.BlockType.BOOLEAN,
+ text: "is modal open?",
+ },
+ {
+ opcode: "modalOpen",
+ blockType: Scratch.BlockType.HAT,
+ text: "when a modal is opened",
+ isEdgeActivated: false,
+ },
+ {
+ opcode: "modalClose",
+ blockType: Scratch.BlockType.HAT,
+ text: "when a modal is closed",
+ isEdgeActivated: false,
+ },
+ {
+ blockType: Scratch.BlockType.EVENT,
+ opcode: "whenButtonPressed",
+ text: "when [BUTTON] is clicked",
+ isEdgeActivated: false, // required boilerplate
+ arguments: {
+ BUTTON: {
+ type: Scratch.ArgumentType.STRING,
+ defaultValue: "My Button",
+ },
+ },
+ },
+ ],
+ };
+ }
+
+ whenButtonPressed(args) {
+ if (buttonPressed == args.BUTTON) {
+ buttonPressed = "";
+ return true;
+ }
+ return false;
+ }
+ addTextToModal(args) {
+ if (isModalOpen) {
+ const text = args.TEXT;
+ //select the first