diff --git a/features/features.json b/features/features.json
index 9588ccbe..caa770ce 100644
--- a/features/features.json
+++ b/features/features.json
@@ -1,4 +1,9 @@
[
+ {
+ "version": 2,
+ "id": "outline-shape-options",
+ "versionAdded": "v4.0.0"
+ },
{
"version": 2,
"id": "more-paint-functions",
diff --git a/features/outline-shape-options/data.json b/features/outline-shape-options/data.json
new file mode 100644
index 00000000..a7606f33
--- /dev/null
+++ b/features/outline-shape-options/data.json
@@ -0,0 +1,25 @@
+{
+ "title": "Customizable Shape Outlines",
+ "description": "Adds more options in the outline dropdown to allow you to customize the shape of the outline, such as making corners round.",
+ "credits": [
+ {
+ "username": "Masaabu-YT",
+ "url": "https://scratch.mit.edu/users/Masaabu-YT/"
+ }
+ ],
+ "type": ["Editor"],
+ "tags": ["New", "Featured"],
+ "dynamic": true,
+ "scripts": [{ "file": "script.js", "runOn": "/projects/*" }],
+ "styles": [{ "file": "style.css", "runOn": "/projects/*" }],
+ "resources": [
+ { "name": "Join-miter", "path": "/resources/join-miter.svg" },
+ { "name": "Join-round", "path": "/resources/join-round.svg" },
+ { "name": "Join-bevel", "path": "/resources/join-bevel.svg" },
+ { "name": "Join-arcs", "path": "/resources/join-arcs.svg" },
+ { "name": "Join-miter-clip", "path": "/resources/join-miter-clip.svg" },
+ { "name": "Cap-butt", "path": "/resources/cap-butt.svg" },
+ { "name": "Cap-round", "path": "/resources/cap-round.svg" },
+ { "name": "Cap-square", "path": "/resources/cap-square.svg" }
+ ]
+}
diff --git a/features/outline-shape-options/resources/cap-butt.svg b/features/outline-shape-options/resources/cap-butt.svg
new file mode 100644
index 00000000..65b4c0e8
--- /dev/null
+++ b/features/outline-shape-options/resources/cap-butt.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/features/outline-shape-options/resources/cap-round.svg b/features/outline-shape-options/resources/cap-round.svg
new file mode 100644
index 00000000..1b0cf28d
--- /dev/null
+++ b/features/outline-shape-options/resources/cap-round.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/features/outline-shape-options/resources/cap-square.svg b/features/outline-shape-options/resources/cap-square.svg
new file mode 100644
index 00000000..c5d67c40
--- /dev/null
+++ b/features/outline-shape-options/resources/cap-square.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/features/outline-shape-options/resources/join-arcs.svg b/features/outline-shape-options/resources/join-arcs.svg
new file mode 100644
index 00000000..65452e9d
--- /dev/null
+++ b/features/outline-shape-options/resources/join-arcs.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/features/outline-shape-options/resources/join-bevel.svg b/features/outline-shape-options/resources/join-bevel.svg
new file mode 100644
index 00000000..e6886775
--- /dev/null
+++ b/features/outline-shape-options/resources/join-bevel.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/features/outline-shape-options/resources/join-miter-clip.svg b/features/outline-shape-options/resources/join-miter-clip.svg
new file mode 100644
index 00000000..6004671c
--- /dev/null
+++ b/features/outline-shape-options/resources/join-miter-clip.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/features/outline-shape-options/resources/join-miter.svg b/features/outline-shape-options/resources/join-miter.svg
new file mode 100644
index 00000000..710ba8f2
--- /dev/null
+++ b/features/outline-shape-options/resources/join-miter.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/features/outline-shape-options/resources/join-round.svg b/features/outline-shape-options/resources/join-round.svg
new file mode 100644
index 00000000..707fb425
--- /dev/null
+++ b/features/outline-shape-options/resources/join-round.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/features/outline-shape-options/script.js b/features/outline-shape-options/script.js
new file mode 100644
index 00000000..f6bcae54
--- /dev/null
+++ b/features/outline-shape-options/script.js
@@ -0,0 +1,80 @@
+export default async function ({ feature, console }) {
+ const icons = {
+ Cap: ["butt", "round", "square"],
+ Join: ["miter", "round", "bevel", "arcs", "miter-clip"],
+ };
+
+ function createSection(type) {
+ const selectedItems = feature.traps.getPaper().project.selectedItems;
+ const result = document.createElement("div");
+ let strokeValue = undefined;
+
+ function changeItems(pos, value) {
+ for (var i in selectedItems) {
+ if (selectedItems[i][pos] !== undefined) {
+ selectedItems[i][pos] = value;
+ }
+ }
+ }
+
+ const row = document.createElement("div");
+ row.classList.add("color-picker_row-header_173LQ");
+ const labelName = document.createElement("span");
+ labelName.classList.add("color-picker_label-name_17igY");
+ labelName.textContent = `Line ${type}`;
+ const labelReadout = document.createElement("span");
+ labelReadout.classList.add("color-picker_label-readout_9vjb2");
+ if (selectedItems.length === 1) {
+ strokeValue = `${selectedItems[0][`stroke${type}`]}`;
+ labelReadout.textContent = strokeValue;
+ }
+ row.appendChild(labelName);
+ row.appendChild(labelReadout);
+
+ const content = document.createElement("div");
+ content.classList.add("color-picker_gradient-picker-row_mnu4O");
+ icons[type].forEach((iconName) => {
+ const icon = document.createElement("img");
+ icon.classList.add(`ste-outline-shape-options-${iconName}`);
+ icon.src = feature.self.getResource(`${type}-${iconName}`);
+ if (iconName !== strokeValue)
+ icon.classList.add("ste-outline-shape-options-passive");
+ icon.addEventListener("click", () => {
+ changeItems(`stroke${type}`, `${iconName}`);
+ labelReadout.textContent = iconName;
+ const elements = content.getElementsByTagName("*");
+ for (let i = 0; i < elements.length; i++) {
+ if (
+ elements[i].classList.contains(
+ `ste-outline-shape-options-${iconName}`
+ )
+ )
+ elements[i].classList.remove("ste-outline-shape-options-passive");
+ else elements[i].classList.add("ste-outline-shape-options-passive");
+ }
+ });
+ content.appendChild(icon);
+ });
+
+ result.appendChild(row);
+ result.appendChild(content);
+ feature.self.hideOnDisable(result)
+ return result;
+ }
+
+ ScratchTools.waitForElements(
+ "div[class*='color-picker_swatch-row_']",
+ function (element) {
+ if (feature.traps.paint().modals.fillColor) return;
+ if (feature.traps.getPaper().project.selectedItems.length < 1) return;
+ const dividerLine = document.createElement("div");
+ dividerLine.classList.add("color-picker_divider_3a3qR");
+ const sectionCap = createSection("Cap");
+ const sectionJoin = createSection("Join");
+
+ element.insertAdjacentElement("afterend", sectionJoin);
+ element.insertAdjacentElement("afterend", sectionCap);
+ element.insertAdjacentElement("afterend", dividerLine);
+ }
+ );
+}
diff --git a/features/outline-shape-options/style.css b/features/outline-shape-options/style.css
new file mode 100644
index 00000000..15c1a549
--- /dev/null
+++ b/features/outline-shape-options/style.css
@@ -0,0 +1,3 @@
+.ste-outline-shape-options-passive {
+ filter: saturate(0%);
+}
\ No newline at end of file