diff --git a/src/backend/looped/self/ptfx.cpp b/src/backend/looped/self/ptfx.cpp
new file mode 100644
index 00000000..35b39508
--- /dev/null
+++ b/src/backend/looped/self/ptfx.cpp
@@ -0,0 +1,39 @@
+#include "natives.hpp"
+#include "backend/looped_command.hpp"
+#include "gta/enums.hpp"
+#include "core/data/ptfx_effects.hpp"
+
+namespace big
+{
+
+	class ptfx_looped : looped_command
+	{
+		using looped_command::looped_command;
+
+		PedBones ptfx_bones[5] = {
+			PedBones::SKEL_Head,
+			PedBones::SKEL_L_Hand,
+			PedBones::SKEL_R_Hand,
+			PedBones::SKEL_L_Foot,
+			PedBones::SKEL_R_Foot
+		};
+
+		void show_ptfx_effect(const char* fx_name, const char* name)
+		{
+			for (const auto& ptfx_bone : ptfx_bones)
+			{
+				STREAMING::REQUEST_NAMED_PTFX_ASSET(fx_name);
+				GRAPHICS::USE_PARTICLE_FX_ASSET(fx_name);
+				GRAPHICS::START_NETWORKED_PARTICLE_FX_NON_LOOPED_ON_PED_BONE(name, self::ped, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.0f, (int)ptfx_bone, g.self.ptfx_effects.size, 1, 1, 1);
+				STREAMING::REMOVE_PTFX_ASSET();
+			}
+		}
+
+		virtual void on_tick() override
+		{
+			show_ptfx_effect(g.self.ptfx_effects.asset, g.self.ptfx_effects.effect);			
+		}
+	};
+
+	ptfx_looped g_ptfx_looped("ptfx", "Enable PTFX", "Show nice PTFX Effects on your character", g.self.ptfx_effects.show);
+}
\ No newline at end of file
diff --git a/src/core/data/ptfx_effects.hpp b/src/core/data/ptfx_effects.hpp
new file mode 100644
index 00000000..bfde6fdb
--- /dev/null
+++ b/src/core/data/ptfx_effects.hpp
@@ -0,0 +1,36 @@
+#pragma once
+
+struct ptfx_library
+{
+	const char* friendly_name;
+	const char* asset_name;
+	std::vector<const char*> effect_names;
+}; 
+
+const ptfx_library ptfx_named[] =  {
+	{ "Agency Heist", "scr_agencyheist", {
+		{ "scr_fbi_mop_drips" },
+		{ "scr_agency3a_door_hvy_trig" },
+		{ "scr_fbi_dd_breach_smoke" },
+	}},
+	{ "Alien", "scr_rcbarry1", {
+		{ "scr_alien_teleport" },
+		{ "scr_alien_disintegrate" },
+	}},
+	{ "Clown", "scr_rcbarry2", {
+		{ "scr_clown_death" },
+		{ "eject_clown" },
+		{ "scr_exp_clown" },
+		{ "scr_clown_appears" },
+		{ "sp_clown_appear_trails" },
+		{ "scr_clown_bul" }, // this one makes noise? lol
+		{ "muz_clown" },
+	}},
+	{ "Firework", "scr_indep_fireworks", {
+		{ "scr_indep_firework_sparkle_spawn" },
+		{ "scr_indep_firework_trailburst_spawn" }, // add seizure warning
+		{ "scr_indep_firework_burst_spawn" },
+		{ "scr_indep_firework_trail_spawn" }
+	}},	
+};
+
diff --git a/src/core/globals.hpp b/src/core/globals.hpp
index 819666a5..51dd45ee 100644
--- a/src/core/globals.hpp
+++ b/src/core/globals.hpp
@@ -6,6 +6,7 @@
 #include "file_manager.hpp"
 #include "backend/reactions/reaction.hpp"
 #include "backend/reactions/interloper_reaction.hpp"
+#include "core/data/ptfx_effects.hpp"
 #include <imgui.h>
 #include <bitset>
 
@@ -238,6 +239,16 @@ namespace big
 
 		struct self 
 		{
+			struct ptfx_effects
+			{
+				bool show = false;
+				float size = 0.2f;
+				int select = 0;
+				const char* asset = "scr_agencyheist";
+				const char* effect = "scr_fbi_mop_drips";
+				NLOHMANN_DEFINE_TYPE_INTRUSIVE(ptfx_effects, show, size)
+			} ptfx_effects {};
+
 			bool clean_player = false;
 			bool force_wanted_level = false;
 			bool free_cam = false;
@@ -278,7 +289,7 @@ namespace big
 			// do not save below entries
 			bool dance_mode = false;
 
-			NLOHMANN_DEFINE_TYPE_INTRUSIVE(self,
+			NLOHMANN_DEFINE_TYPE_INTRUSIVE(self, ptfx_effects,
 				clean_player, force_wanted_level, free_cam, invisibility, local_visibility, never_wanted, no_ragdoll,
 				noclip, off_radar, super_run, no_collision, unlimited_oxygen, no_water_collision, wanted_level, god_mode, part_water,
 				proof_bullet, proof_fire, proof_collision, proof_melee, proof_explosion, proof_steam, proof_drown, proof_water,
diff --git a/src/views/self/view_self.cpp b/src/views/self/view_self.cpp
index 5443eab4..33cb2aa3 100644
--- a/src/views/self/view_self.cpp
+++ b/src/views/self/view_self.cpp
@@ -4,6 +4,7 @@
 #include "views/view.hpp"
 #include "core/data/hud_component_names.hpp"
 #include "util/scripts.hpp"
+#include "core/data/ptfx_effects.hpp"
 
 namespace big
 {
@@ -60,6 +61,47 @@ namespace big
 
 		ImGui::EndGroup();
 
+		components::sub_title("PTFX Styles");
+
+		components::command_checkbox<"ptfx">();
+		if (g.self.ptfx_effects.show)
+		{
+			ImGui::SliderFloat("PTFX Size", &g.self.ptfx_effects.size, 0.1f, 2.f);
+			if (ImGui::BeginCombo("Asset", ptfx_named[g.self.ptfx_effects.select].friendly_name))
+			{
+				for (int i = 0; i < IM_ARRAYSIZE(ptfx_named); i++)
+				{
+					if (ImGui::Selectable(ptfx_named[i].friendly_name, ptfx_named[i].asset_name == g.self.ptfx_effects.asset))
+					{
+						g.self.ptfx_effects.asset = ptfx_named[i].asset_name; // Update our asset name to be used
+						g.self.ptfx_effects.select = i;
+						g.self.ptfx_effects.effect = ptfx_named[i].effect_names.at(0); // set the effect to the first instance in the vector
+					}
+
+					if (ptfx_named[i].asset_name == g.self.ptfx_effects.asset)
+						ImGui::SetItemDefaultFocus();
+				}
+
+				ImGui::EndCombo();
+			}
+
+			if (ImGui::BeginCombo("Effect", g.self.ptfx_effects.effect))
+			{
+				for (const auto& ptfx_type : ptfx_named[g.self.ptfx_effects.select].effect_names)
+				{
+					if (ImGui::Selectable(ptfx_type, ptfx_type == g.self.ptfx_effects.effect))
+						g.self.ptfx_effects.effect = ptfx_type; // Update our ptfx effect
+
+					if (ptfx_type == g.self.ptfx_effects.effect)
+						ImGui::SetItemDefaultFocus();
+				}
+
+				ImGui::EndCombo();
+			}
+				
+		}
+
+	
 		ImGui::Separator();
 
 		components::sub_title("PROOFS"_T);