diff --git a/BondageClub/Assets/Female3DCG/Female3DCGExtended.js b/BondageClub/Assets/Female3DCG/Female3DCGExtended.js
index 44aaf3a7ee2884a4255b1f6cd2b551e6ad01208a..32a2b7fbfbac73f08200c54b908369ca79a047a0 100644
--- a/BondageClub/Assets/Female3DCG/Female3DCGExtended.js
+++ b/BondageClub/Assets/Female3DCG/Female3DCGExtended.js
@@ -4246,6 +4246,32 @@ var AssetFemale3DCGExtended = {
 				],
 			},
 		}, //LockingSwimsuit
+		FuturisticHarness: {
+			Archetype: ExtendedArchetype.TYPED,
+			Config: {
+				Options: [
+					{
+						Name: "Full",
+						Property: { Type: null, Difficulty: 2 },
+					},
+					{
+						Name: "Upper",
+						Property: { Type: "Upper", Difficulty: 0 },
+					},
+					{
+						Name: "Lower",
+						Property: { Type: "Lower", Difficulty: 0 },
+					},
+				],
+				ScriptHooks: {
+					Load: FuturisticAccessLoad,
+					Click: InventoryItemTorsoFuturisticHarnessClick,
+					Draw: InventoryItemTorsoFuturisticHarnessDraw,
+					Exit: FuturisticAccessExit,
+					Validate: FuturisticAccessValidate,
+				},
+			},
+		}, // FuturisticHarness
 	}, // ItemTorso
 	ItemTorso2: {
 		LockingSwimsuit: {
@@ -4284,6 +4310,17 @@ var AssetFemale3DCGExtended = {
 			Archetype: ExtendedArchetype.TYPED,
 			CopyConfig: { GroupName: "ItemTorso", AssetName: "ThinLeatherStraps" },
 		}, // ThinLeatherStraps
+		FuturisticHarness: {
+			Archetype: ExtendedArchetype.TYPED,
+			CopyConfig: { GroupName: "ItemTorso", AssetName: "FuturisticHarness" },
+			Config: {
+				Dialog: {
+					Load: "ItemTorsoFuturisticHarnessSelect",
+					TypePrefix: "ItemTorsoFuturisticHarness",
+					ChatPrefix: "ItemTorsoFuturisticHarnessSet",
+				},
+			}
+		}, // FuturisticHarness
 	}, //ItemTorso2
 	Shoes: {
 		FuturisticHeels2: {
diff --git a/BondageClub/Assets/Female3DCG/LayerNames.csv b/BondageClub/Assets/Female3DCG/LayerNames.csv
index d9b6586e63808c4521573131adc8fd5d6d8e67e1..dd7a177f0790a00f0788c6ce0b38af5109fdec3c 100644
--- a/BondageClub/Assets/Female3DCG/LayerNames.csv
+++ b/BondageClub/Assets/Female3DCG/LayerNames.csv
@@ -1109,6 +1109,10 @@ ItemTorsoFuturisticHarnessBand,Straps
 ItemTorsoFuturisticHarnessDisplay,Display
 ItemTorsoFuturisticHarnessMesh,Module
 ItemTorsoFuturisticHarnessLock,Lock
+ItemTorso2FuturisticHarnessBand,Straps
+ItemTorso2FuturisticHarnessDisplay,Display
+ItemTorso2FuturisticHarnessMesh,Module
+ItemTorso2FuturisticHarnessLock,Lock
 ItemBreastFuturisticBraBra,Body
 ItemBreastFuturisticBraDisplay,Display
 ItemBreastFuturisticBraMesh,Mesh
diff --git a/BondageClub/Screens/Character/Player/Dialog_Player.csv b/BondageClub/Screens/Character/Player/Dialog_Player.csv
index a793f11180a454cb8f58e7737abfbea19a74f5ac..12c7b52f56cc5626a7732ac315eb4f667473c2d1 100644
--- a/BondageClub/Screens/Character/Player/Dialog_Player.csv
+++ b/BondageClub/Screens/Character/Player/Dialog_Player.csv
@@ -1130,13 +1130,13 @@ ItemDevicesFuturisticCrateSeth1,,,SourceCharacter configures the harness on Dest
 ItemDevicesFuturisticCrateSeth2,,,SourceCharacter configures the harness on DestinationCharacter crate.,,
 ItemDevicesFuturisticCrateSeth3,,,SourceCharacter configures the harness on DestinationCharacter crate.,,
 ItemDevicesFuturisticCrateSeth4,,,SourceCharacter configures the harness on DestinationCharacter crate.,,
-FuturisticHarnessType,,,Select device mode:,,
-FuturisticHarnessTypeFull,,,Full,,
-FuturisticHarnessTypeUpper,,,Upper,,
-FuturisticHarnessTypeLower,,,Lower,,
-FuturisticHarnessSetLower,,,SourceCharacter moves DestinationCharacter harness to the lower body.,,
-FuturisticHarnessSetUpper,,,SourceCharacter moves DestinationCharacter harness to the upper body.,,
-FuturisticHarnessSetFull,,,SourceCharacter configures DestinationCharacter harness to surround the whole body in straps.,,
+ItemTorsoFuturisticHarnessSelect,,,Select device mode:,,
+ItemTorsoFuturisticHarnessFull,,,Full,,
+ItemTorsoFuturisticHarnessUpper,,,Upper,,
+ItemTorsoFuturisticHarnessLower,,,Lower,,
+ItemTorsoFuturisticHarnessSetLower,,,SourceCharacter moves DestinationCharacter harness to the lower body.,,
+ItemTorsoFuturisticHarnessSetUpper,,,SourceCharacter moves DestinationCharacter harness to the upper body.,,
+ItemTorsoFuturisticHarnessSetFull,,,SourceCharacter configures DestinationCharacter harness to surround the whole body in straps.,,
 HighSecurityHarnessType,,,Select device mode:,,
 HighSecurityHarnessTypeLowSec,,,Belt,,
 HighSecurityHarnessTypeMedSec,,,Pelvis,,
diff --git a/BondageClub/Screens/Inventory/Futuristic/Futuristic.js b/BondageClub/Screens/Inventory/Futuristic/Futuristic.js
index c5c3d59617315baaf47360d717f6125a37384846..89bee68c245f3e500db05cc066c4f603ae733ab2 100644
--- a/BondageClub/Screens/Inventory/Futuristic/Futuristic.js
+++ b/BondageClub/Screens/Inventory/Futuristic/Futuristic.js
@@ -45,39 +45,47 @@ var FuturisticAccessLegGroups = ["ItemLegs", "ItemFeet", "ItemBoots"];
 var FuturisticAccessChastityGroups = ["ItemPelvis", "ItemTorso", "ItemButt", "ItemVulva", "ItemVulvaPiercings", "ItemBreast", "ItemNipples", "ItemNipplesPiercings"];
 
 /**
- * Hook script for injecting futuristic features into an archetypical item
- * @param {function} OriginalFunction - The function that is normally called when an archetypical item reaches this point.
- * @returns {void} - Nothing
+ * Helper function for the futuristic hook scripts.
+ * @param {() => void} OriginalFunction - The function that is normally called when an archetypical item reaches this point.
+ * @param {() => void} DeniedFunction - The function that is called when validation fails.
+ * @returns {boolean} - Whether the validation was successful or not.
  */
-function FuturisticAccessLoad(OriginalFunction) {
+function FuturisticAccess(OriginalFunction, DeniedFunction) {
 	var C = CharacterGetCurrent();
 	if (InventoryItemFuturisticValidate(C) !== "") {
-		InventoryItemFuturisticLoadAccessDenied()
-	} else OriginalFunction();
+		DeniedFunction();
+		return false;
+	} else {
+		OriginalFunction();
+		return true;
+	}
 }
 
 /**
  * Hook script for injecting futuristic features into an archetypical item
- * @param {function} OriginalFunction - The function that is normally called when an archetypical item reaches this point.
- * @returns {void} - Nothing
+ * @param {() => void} OriginalFunction - The function that is normally called when an archetypical item reaches this point.
+ * @returns {boolean} - Whether the validation was successful or not.
+ */
+function FuturisticAccessLoad(OriginalFunction) {
+	return FuturisticAccess(OriginalFunction, InventoryItemFuturisticLoadAccessDenied);
+}
+
+/**
+ * Hook script for injecting futuristic features into an archetypical item
+ * @param {() => void} OriginalFunction - The function that is normally called when an archetypical item reaches this point.
+ * @returns {boolean} - Whether the validation was successful or not.
  */
 function FuturisticAccessClick(OriginalFunction) {
-	var C = CharacterGetCurrent();
-	if (InventoryItemFuturisticValidate(C) !== "") {
-		InventoryItemFuturisticClickAccessDenied()
-	} else OriginalFunction();
+	return FuturisticAccess(OriginalFunction, InventoryItemFuturisticClickAccessDenied);
 }
 
 /**
  * Hook script for injecting futuristic features into an archetypical item
- * @param {function} OriginalFunction - The function that is normally called when an archetypical item reaches this point.
- * @returns {void} - Nothing
+ * @param {() => void} OriginalFunction - The function that is normally called when an archetypical item reaches this point.
+ * @returns {boolean} - Whether the validation was successful or not.
  */
 function FuturisticAccessDraw(OriginalFunction) {
-	var C = CharacterGetCurrent();
-	if (InventoryItemFuturisticValidate(C) !== "") {
-		InventoryItemFuturisticDrawAccessDenied()
-	} else OriginalFunction();
+	return FuturisticAccess(OriginalFunction, InventoryItemFuturisticDrawAccessDenied);
 }
 
 /**
diff --git a/BondageClub/Screens/Inventory/ItemTorso/FuturisticHarness/FuturisticHarness.js b/BondageClub/Screens/Inventory/ItemTorso/FuturisticHarness/FuturisticHarness.js
index fc5898b42fde5caee387a217efef3c4cfa088252..63ee5112ed99e8d0b0f92c38cfc1ea96d37083ab 100644
--- a/BondageClub/Screens/Inventory/ItemTorso/FuturisticHarness/FuturisticHarness.js
+++ b/BondageClub/Screens/Inventory/ItemTorso/FuturisticHarness/FuturisticHarness.js
@@ -1,71 +1,36 @@
 "use strict";
 
-var InventoryItemTorsoFuturisticHarnessOptions = [
-	{
-		Name: "Full",
-		Property: { Type: null, Difficulty: 2},
-	},
-	{
-		Name: "Upper",
-		Property: { Type: "Upper", Difficulty: 0},
-	},
-	{
-		Name: "Lower",
-		Property: { Type: "Lower", Difficulty: 0},
-	},
-];
-
-// Loads the item extension properties
-function InventoryItemTorsoFuturisticHarnessLoad() {
-	var C = CharacterGetCurrent();
-	if (InventoryItemFuturisticValidate(C) !== "") {
-		InventoryItemFuturisticLoadAccessDenied();
-	}  else
-		ExtendedItemLoad(InventoryItemTorsoFuturisticHarnessOptions, "FuturisticHarnessType");
-}
-
-// Draw the item extension screen
-function InventoryItemTorsoFuturisticHarnessDraw() {
-	var C = CharacterGetCurrent();
-	if (InventoryItemFuturisticValidate(C) !== "") {
-		InventoryItemFuturisticDrawAccessDenied();
-	} else {
-		ExtendedItemDraw(InventoryItemTorsoFuturisticHarnessOptions, "FuturisticHarnessType");
-
-		DrawAssetPreview(1387, 75, DialogFocusItem.Asset);
-
-		var FuturisticCollarItems = InventoryItemNeckFuturisticCollarGetItems(C);
-
-		if (FuturisticCollarItems.length > 0) {
-			DrawButton(1400, 910, 200, 55, DialogFindPlayer("FuturisticCollarColor"), "White");
-		}
+/**
+ * Draw the item extension screen
+ * @param {() => void} OriginalFunction - The function that is normally called when an archetypical item reaches this point.
+ * @returns {void} - Nothing
+ */
+function InventoryItemTorsoFuturisticHarnessDraw(OriginalFunction) {
+	if (!FuturisticAccessDraw(OriginalFunction)) {
+		return;
+	}
+	const C = CharacterGetCurrent();
+	const FuturisticCollarItems = InventoryItemNeckFuturisticCollarGetItems(C);
+	if (FuturisticCollarItems.length > 0) {
+		DrawButton(1385, 800, 225, 55, DialogFindPlayer("FuturisticCollarColor"), "White");
 	}
 }
 
-
-function InventoryItemTorsoFuturisticHarnessPublishAction(C, Option) {
-	var msg = "FuturisticHarnessSet" + Option.Name;
-	var Dictionary = [
-		{ Tag: "SourceCharacter", Text: CharacterNickname(Player), MemberNumber: Player.MemberNumber },
-		{ Tag: "DestinationCharacter", Text: CharacterNickname(C), MemberNumber: C.MemberNumber },
-	];
-	ChatRoomPublishCustomAction(msg, true, Dictionary);
-}
-
-// Catches the item extension clicks
-function InventoryItemTorsoFuturisticHarnessClick() {
-	var C = CharacterGetCurrent();
-	if (InventoryItemFuturisticValidate(C) !== "") {
-		InventoryItemFuturisticClickAccessDenied();
-	} else {
-
-		ExtendedItemClick(InventoryItemTorsoFuturisticHarnessOptions);
-
-		var FuturisticCollarItems = InventoryItemNeckFuturisticCollarGetItems(C);
-		if (MouseIn(1400, 910, 200, 55) && FuturisticCollarItems.length > 0 && DialogFocusItem) { InventoryItemNeckFuturisticCollarColor(C, DialogFocusItem); InventoryItemTorsoFuturisticHarnessExit();}
+/**
+ * Catches the item extension clicks
+ * @param {() => void} OriginalFunction - The function that is normally called when an archetypical item reaches this point.
+ * @returns {void} - Nothing
+ */
+function InventoryItemTorsoFuturisticHarnessClick(OriginalFunction) {
+	if (!FuturisticAccessClick(OriginalFunction)) {
+		return;
+	}
+	if (MouseIn(1385, 800, 225, 55)) {
+		const C = CharacterGetCurrent();
+		const FuturisticCollarItems = InventoryItemNeckFuturisticCollarGetItems(C);
+		if (FuturisticCollarItems.length > 0 && DialogFocusItem) {
+			InventoryItemNeckFuturisticCollarColor(C, DialogFocusItem);
+			FuturisticAccessExit();
+		}
 	}
 }
-
-function InventoryItemTorsoFuturisticHarnessExit() {
-	InventoryItemFuturisticExitAccessDenied();
-}
\ No newline at end of file
diff --git a/BondageClub/Screens/Inventory/ItemTorso2/FuturisticHarness/FuturisticHarness.js b/BondageClub/Screens/Inventory/ItemTorso2/FuturisticHarness/FuturisticHarness.js
deleted file mode 100644
index 8a6b7d569c553b9cf9529a1c22a27cb52763d1bf..0000000000000000000000000000000000000000
--- a/BondageClub/Screens/Inventory/ItemTorso2/FuturisticHarness/FuturisticHarness.js
+++ /dev/null
@@ -1,71 +0,0 @@
-"use strict";
-
-var InventoryItemTorso2FuturisticHarnessOptions = [
-	{
-		Name: "Full",
-		Property: { Type: null, Difficulty: 2},
-	},
-	{
-		Name: "Upper",
-		Property: { Type: "Upper", Difficulty: 0},
-	},
-	{
-		Name: "Lower",
-		Property: { Type: "Lower", Difficulty: 0},
-	},
-];
-
-// Loads the item extension properties
-function InventoryItemTorso2FuturisticHarnessLoad() {
-	var C = CharacterGetCurrent();
-	if (InventoryItemFuturisticValidate(C) !== "") {
-		InventoryItemFuturisticLoadAccessDenied();
-	}  else
-		ExtendedItemLoad(InventoryItemTorso2FuturisticHarnessOptions, "FuturisticHarnessType");
-}
-
-// Draw the item extension screen
-function InventoryItemTorso2FuturisticHarnessDraw() {
-	var C = CharacterGetCurrent();
-	if (InventoryItemFuturisticValidate(C) !== "") {
-		InventoryItemFuturisticDrawAccessDenied();
-	} else {
-		ExtendedItemDraw(InventoryItemTorso2FuturisticHarnessOptions, "FuturisticHarnessType");
-
-		DrawAssetPreview(1387, 75, DialogFocusItem.Asset);
-
-		var FuturisticCollarItems = InventoryItemNeckFuturisticCollarGetItems(C);
-
-		if (FuturisticCollarItems.length > 0) {
-			DrawButton(1400, 910, 200, 55, DialogFindPlayer("FuturisticCollarColor"), "White");
-		}
-	}
-}
-
-
-function InventoryItemTorso2FuturisticHarnessPublishAction(C, Option) {
-	var msg = "FuturisticHarnessSet" + Option.Name;
-	var Dictionary = [
-		{ Tag: "SourceCharacter", Text: CharacterNickname(Player), MemberNumber: Player.MemberNumber },
-		{ Tag: "DestinationCharacter", Text: CharacterNickname(C), MemberNumber: C.MemberNumber },
-	];
-	ChatRoomPublishCustomAction(msg, true, Dictionary);
-}
-
-// Catches the item extension clicks
-function InventoryItemTorso2FuturisticHarnessClick() {
-	var C = CharacterGetCurrent();
-	if (InventoryItemFuturisticValidate(C) !== "") {
-		InventoryItemFuturisticClickAccessDenied();
-	} else {
-
-		ExtendedItemClick(InventoryItemTorso2FuturisticHarnessOptions);
-
-		var FuturisticCollarItems = InventoryItemNeckFuturisticCollarGetItems(C);
-		if (MouseIn(1400, 910, 200, 55) && FuturisticCollarItems.length > 0 && DialogFocusItem) { InventoryItemNeckFuturisticCollarColor(C, DialogFocusItem); InventoryItemTorso2FuturisticHarnessExit();}
-	}
-}
-
-function InventoryItemTorso2FuturisticHarnessExit() {
-	InventoryItemFuturisticExitAccessDenied();
-}
\ No newline at end of file
diff --git a/BondageClub/Scripts/Inventory.js b/BondageClub/Scripts/Inventory.js
index 3907342f71448e1ecbe0528c1880053b09d20b51..72f6b9af86b92826330031255fbc279a764c2a79 100644
--- a/BondageClub/Scripts/Inventory.js
+++ b/BondageClub/Scripts/Inventory.js
@@ -534,16 +534,7 @@ function InventoryWearCraftModular(Item, Type) {
 * @returns {void}
 */
 function InventoryWearCraftTyped(Item, Type) {
-	const Config = AssetFemale3DCGExtended[Item.Asset.Group.Name][Item.Asset.Name].Config;
-	if ((Config == null) || (Config.Options == null)) {
-		return;
-	}
-	for (const O of Config.Options) {
-		if (O.Name == Type) {
-			Item.Property = JSON.parse(JSON.stringify(O.Property));
-			return;
-		}
-	}
+	TypedItemSetOptionByName(CharacterGetCurrent(), Item, Type);
 }
 
 /**
diff --git a/BondageClub/Scripts/Typedef.d.ts b/BondageClub/Scripts/Typedef.d.ts
index dae4e3db9103f64dbf9de67d9defff4d67366e17..b853b95b9fb6670fe37027c62a0fd1729bf71d73 100644
--- a/BondageClub/Scripts/Typedef.d.ts
+++ b/BondageClub/Scripts/Typedef.d.ts
@@ -1668,7 +1668,7 @@ type ModularItemAssetConfig = ExtendedItemAssetConfig<"modular", ModularItemConf
 /** An object defining all of the required configuration for registering a modular item */
 interface ModularItemConfig {
 	/** The module definitions for the item */
-	Modules: ModularItemModule[];
+	Modules?: ModularItemModule[];
 	/**
 	 * The item's chatroom message setting. Determines the level of
 	 * granularity for chatroom messages when the item's module values change.
@@ -1689,7 +1689,8 @@ interface ModularItemConfig {
 	Dialog?: ModularItemDialogConfig;
 	/**
 	 * A recond containing functions that are run on load, click, draw, exit, and validate, with the original archetype function
-	 * and parameters passed on to them. If undefined, these are ignored
+	 * and parameters passed on to them. If undefined, these are ignored.
+	 * Note that scripthook functions must be loaded before `Female3DCGExtended.js` in `index.html`.
 	 */
 	ScriptHooks?: {
 		Load?: (next: () => void) => void;
@@ -1835,7 +1836,8 @@ interface ModularItemData {
 	changeWhenLocked: boolean;
 	/**
 	 * A recond containing functions that are run on load, click, draw, exit, and validate, with the original archetype function
-	 * and parameters passed on to them. If undefined, these are ignored
+	 * and parameters passed on to them. If undefined, these are ignored.
+	 * Note that scripthook functions must be loaded before `Female3DCGExtended.js` in `index.html`.
 	 */
 	scriptHooks?: {
 		load?: (next: () => void) => void,
@@ -1867,7 +1869,7 @@ type TypedItemAssetConfig = ExtendedItemAssetConfig<"typed", TypedItemConfig>;
 /** An object defining all of the required configuration for registering a typed item */
 interface TypedItemConfig {
 	/** The list of extended item options available for the item */
-	Options: ExtendedItemOption[];
+	Options?: ExtendedItemOption[];
 	/** The optional text configuration for the item. Custom text keys can be configured within this object */
 	Dialog?: TypedItemDialogConfig;
 	/**
@@ -1899,7 +1901,8 @@ interface TypedItemConfig {
 	Dictionary?: TypedItemDictionaryCallback[];
 	/**
 	 * A recond containing functions that are run on load, click, draw, exit, and validate, with the original archetype function
-	 * and parameters passed on to them. If undefined, these are ignored
+	 * and parameters passed on to them. If undefined, these are ignored.
+	 * Note that scripthook functions must be loaded before `Female3DCGExtended.js` in `index.html`.
 	 */
 	ScriptHooks?: {
 		Load?: (next: () => void) => void,
@@ -1989,7 +1992,8 @@ interface TypedItemData {
 	validate?: ExtendedItemValidateCallback<ExtendedItemOption>;
 	/**
 	 * A recond containing functions that are run on load, click, draw, exit, and validate, with the original archetype function
-	 * and parameters passed on to them. If undefined, these are ignored
+	 * and parameters passed on to them. If undefined, these are ignored.
+	 * Note that scripthook functions must be loaded before `Female3DCGExtended.js` in `index.html`.
 	 */
 	scriptHooks?: {
 		load?: (next: () => void) => void,
diff --git a/BondageClub/index.html b/BondageClub/index.html
index 212d62ebb9a946af6eeb2b1dd0bb8961660cde33..a347f9042187b1c39bd3fb20a92f33c13e8a3710 100644
--- a/BondageClub/index.html
+++ b/BondageClub/index.html
@@ -64,6 +64,7 @@
 <script src="Scripts/VariableHeight.js"></script>
 <script src="Assets/Female3DCG/Female3DCG.js"></script>
 <script src="Screens/Inventory/Futuristic/Futuristic.js"></script>
+<script src="Screens/Inventory/ItemTorso/FuturisticHarness/FuturisticHarness.js"></script>
 <script src="Assets/Female3DCG/Female3DCGExtended.js"></script>
 <script src="Screens/Character/Login/Login.js"></script>
 <script src="Screens/Character/Appearance/Appearance.js"></script>
@@ -193,8 +194,6 @@
 <script src="Screens/Inventory/ItemMouth/FuturisticHarnessPanelGag/FuturisticHarnessPanelGag.js"></script>
 <script src="Screens/Inventory/ItemMouth/FuturisticHarnessBallGag/FuturisticHarnessBallGag.js"></script>
 <script src="Screens/Inventory/ItemNeck/FuturisticCollar/FuturisticCollar.js"></script>
-<script src="Screens/Inventory/ItemTorso/FuturisticHarness/FuturisticHarness.js"></script>
-<script src="Screens/Inventory/ItemTorso2/FuturisticHarness/FuturisticHarness.js"></script>
 <script src="Screens/Inventory/ItemHands/SpankingToys/SpankingToy.js"></script>
 <script src="Screens/Inventory/ItemFeet/HempRope/HempRope.js"></script>
 <script src="Screens/Inventory/ItemFeet/NylonRope/NylonRope.js"></script>