Tornado V6
Key RequiredUniversal

Tornado V6

Universal ScriptVoidX5VoidX5 7.6K views 2.1K executesUpdated Mar 3, 2026
5.0/ 5(3 votes)
30100% Positive
Lua Script•375 lines (15985 chars)
-- =========================================================
-- ULTIMATE TORNADO ENGINE V6 (DYNAMIC PHYSICS DROPDOWN)
-- =========================================================
local RunService = game:GetService("RunService")
local PathfindingService = game:GetService("PathfindingService")
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local Player = Players.LocalPlayer

-- System Variables
local TornadoActive = false
local TornadoModel = nil
local FunnelSegments = {}
local CurrentPath = {}
local CurrentWaypoint = 1

-- CUSTOMIZATION SETTINGS (10+ Options)
local Settings = {
	EF_Level = 1,
	WanderSpeed = 25,
	PhysicsMode = "Original", -- NEW MODE TOGGLE
	PullStrengthMult = 1.0,
	RadiusMult = 1.0,
	LiftSpeed = 1.0,
	RotationSpeed = 1.0,
	DebrisDensity = 100,
	FunnelTrans = 0.6,
	Color_R = 100,
	Color_G = 100,
	Color_B = 105,
}

local EF_STATS = {
	[1] = {Radius = 60, Strength = 40, Height = 150, Scale = 1},
	[2] = {Radius = 100, Strength = 70, Height = 220, Scale = 1.6},
	[3] = {Radius = 160, Strength = 120, Height = 320, Scale = 2.4},
	[4] = {Radius = 240, Strength = 200, Height = 450, Scale = 3.5},
	[5] = {Radius = 350, Strength = 320, Height = 600, Scale = 5.0}
}

-- =========================================================
-- 1. ADVANCED TABBED GUI SYSTEM
-- =========================================================
local ScreenGui = Instance.new("ScreenGui", Player:WaitForChild("PlayerGui"))
ScreenGui.Name = "StormOS"
ScreenGui.ResetOnSpawn = false

local MainFrame = Instance.new("Frame", ScreenGui)
MainFrame.Size, MainFrame.Position = UDim2.new(0, 360, 0, 480), UDim2.new(1, -380, 0.5, -240)
MainFrame.BackgroundColor3 = Color3.fromRGB(15, 15, 18)
MainFrame.Active = true
Instance.new("UICorner", MainFrame).CornerRadius = UDim.new(0, 12)
Instance.new("UIStroke", MainFrame).Color = Color3.fromRGB(80, 140, 255)

-- Draggable Logic
local dragging, dragInput, dragStart, startPos
MainFrame.InputBegan:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		dragging = true dragStart = input.Position startPos = MainFrame.Position
		input.Changed:Connect(function() if input.UserInputState == Enum.UserInputState.End then dragging = false end end)
	end
end)
MainFrame.InputChanged:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseMovement then dragInput = input end
end)
UserInputService.InputChanged:Connect(function(input)
	if input == dragInput and dragging then
		local delta = input.Position - dragStart
		MainFrame.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
	end
end)

local Title = Instance.new("TextLabel", MainFrame)
Title.Size, Title.Text = UDim2.new(1, 0, 0, 40), "STORM OS v6.0"
Title.Font, Title.TextColor3, Title.TextSize = Enum.Font.GothamBlack, Color3.new(1,1,1), 16
Title.BackgroundTransparency = 1

-- Tabs
local TabContainer = Instance.new("Frame", MainFrame)
TabContainer.Size, TabContainer.Position = UDim2.new(1, -20, 0, 35), UDim2.new(0, 10, 0, 40)
TabContainer.BackgroundTransparency = 1
local TabLayout = Instance.new("UIListLayout", TabContainer)
TabLayout.FillDirection, TabLayout.Padding = Enum.FillDirection.Horizontal, UDim.new(0, 5)

local ContentArea = Instance.new("Frame", MainFrame)
ContentArea.Size, ContentArea.Position = UDim2.new(1, -20, 1, -95), UDim2.new(0, 10, 0, 85)
ContentArea.BackgroundColor3 = Color3.fromRGB(22, 22, 26)
Instance.new("UICorner", ContentArea)

local Tabs = {}
local function CreateTab(name)
	local btn = Instance.new("TextButton", TabContainer)
	btn.Size, btn.Text, btn.BackgroundColor3 = UDim2.new(0.31, 0, 1, 0), name, Color3.fromRGB(30, 30, 35)
	btn.TextColor3, btn.Font, btn.TextSize = Color3.new(0.7,0.7,0.7), Enum.Font.GothamBold, 12
	Instance.new("UICorner", btn)
	
	local frame = Instance.new("ScrollingFrame", ContentArea)
	frame.Size, frame.BackgroundTransparency = UDim2.new(1, -10, 1, -10), 1
	frame.Position = UDim2.new(0, 5, 0, 5)
	frame.ScrollBarThickness, frame.Visible = 2, false
	local layout = Instance.new("UIListLayout", frame)
	layout.Padding, layout.HorizontalAlignment = UDim.new(0, 8), Enum.HorizontalAlignment.Center
	
	btn.MouseButton1Click:Connect(function()
		for _, t in pairs(Tabs) do t.Btn.BackgroundColor3 = Color3.fromRGB(30,30,35) t.Btn.TextColor3 = Color3.new(0.7,0.7,0.7) t.Frame.Visible = false end
		btn.BackgroundColor3 = Color3.fromRGB(80, 140, 255)
		btn.TextColor3 = Color3.new(1,1,1)
		frame.Visible = true
	end)
	
	table.insert(Tabs, {Btn = btn, Frame = frame})
	return frame
end

local TabControl = CreateTab("CONTROL")
local TabPhysics = CreateTab("PHYSICS")
local TabVisuals = CreateTab("VISUALS")
Tabs[1].Btn.BackgroundColor3 = Color3.fromRGB(80, 140, 255)
Tabs[1].Btn.TextColor3 = Color3.new(1,1,1)
TabControl.Visible = true

-- Helper to make setting rows
local function CreateSetting(parent, text, settingKey, min, max, step)
	local row = Instance.new("Frame", parent)
	row.Size, row.BackgroundTransparency = UDim2.new(1, 0, 0, 35), 1
	local lbl = Instance.new("TextLabel", row)
	lbl.Size, lbl.Text, lbl.TextColor3 = UDim2.new(0.6, 0, 1, 0), text, Color3.new(0.9,0.9,0.9)
	lbl.BackgroundTransparency, lbl.Font, lbl.TextXAlignment = 1, Enum.Font.Gotham, Enum.TextXAlignment.Left
	
	local valLbl = Instance.new("TextLabel", row)
	valLbl.Size, valLbl.Position, valLbl.Text = UDim2.new(0.2, 0, 1, 0), UDim2.new(0.6, 0, 0, 0), tostring(Settings[settingKey])
	valLbl.BackgroundTransparency, valLbl.TextColor3, valLbl.Font = 1, Color3.fromRGB(80, 140, 255), Enum.Font.GothamBold
	
	local minus = Instance.new("TextButton", row)
	minus.Size, minus.Position, minus.Text, minus.BackgroundColor3 = UDim2.new(0, 25, 0, 25), UDim2.new(0.8, 0, 0.5, -12), "-", Color3.fromRGB(40,40,45)
	minus.TextColor3, minus.Font = Color3.new(1,1,1), Enum.Font.GothamBold
	Instance.new("UICorner", minus)
	
	local plus = Instance.new("TextButton", row)
	plus.Size, plus.Position, plus.Text, plus.BackgroundColor3 = UDim2.new(0, 25, 0, 25), UDim2.new(0.9, 0, 0.5, -12), "+", Color3.fromRGB(40,40,45)
	plus.TextColor3, plus.Font = Color3.new(1,1,1), Enum.Font.GothamBold
	Instance.new("UICorner", plus)
	
	local function update(change)
		Settings[settingKey] = math.clamp(Settings[settingKey] + change, min, max)
		valLbl.Text = tostring(math.floor(Settings[settingKey]*10)/10)
		if settingKey == "Color_R" or settingKey == "Color_G" or settingKey == "Color_B" or settingKey == "FunnelTrans" then
			if TornadoModel then UpdateVisuals() end
		end
	end
	
	minus.MouseButton1Click:Connect(function() update(-step) end)
	plus.MouseButton1Click:Connect(function() update(step) end)
end

-- NEW DROPDOWN MENU CREATOR
local function CreateDropdown(parent, text, settingKey, options)
	local row = Instance.new("Frame", parent)
	row.Size, row.BackgroundTransparency = UDim2.new(1, 0, 0, 35), 1
	row.ClipsDescendants = false
	
	local lbl = Instance.new("TextLabel", row)
	lbl.Size, lbl.Text, lbl.TextColor3 = UDim2.new(0.5, 0, 1, 0), text, Color3.new(0.9,0.9,0.9)
	lbl.BackgroundTransparency, lbl.Font, lbl.TextXAlignment = 1, Enum.Font.Gotham, Enum.TextXAlignment.Left
	
	local dropBtn = Instance.new("TextButton", row)
	dropBtn.Size, dropBtn.Position, dropBtn.Text = UDim2.new(0.5, 0, 0.8, 0), UDim2.new(0.5, 0, 0.1, 0), Settings[settingKey]
	dropBtn.BackgroundColor3, dropBtn.TextColor3 = Color3.fromRGB(40, 40, 45), Color3.new(1,1,1)
	dropBtn.Font = Enum.Font.GothamBold
	Instance.new("UICorner", dropBtn)
	
	-- Dropdown behavior (Cycles options on click to prevent clipping issues in scrolling frames)
	local currentIndex = 1
	dropBtn.MouseButton1Click:Connect(function()
		currentIndex = currentIndex + 1
		if currentIndex > #options then currentIndex = 1 end
		Settings[settingKey] = options[currentIndex]
		dropBtn.Text = options[currentIndex]
		
		-- Visual flair when changed
		dropBtn.BackgroundColor3 = Color3.fromRGB(80, 140, 255)
		task.wait(0.1)
		dropBtn.BackgroundColor3 = Color3.fromRGB(40, 40, 45)
	end)
end

local function CreateActionBtn(parent, text, color, callback)
	local b = Instance.new("TextButton", parent)
	b.Size, b.BackgroundColor3, b.Text = UDim2.new(1, 0, 0, 45), color, text
	b.Font, b.TextColor3, b.TextSize = Enum.Font.GothamBold, Color3.new(1,1,1), 14
	Instance.new("UICorner", b)
	b.MouseButton1Click:Connect(callback)
end

-- Populate UI
CreateActionBtn(TabControl, "SPAWN TORNADO", Color3.fromRGB(40, 180, 80), function() GenerateTornado() end)
CreateActionBtn(TabControl, "DESPAWN TORNADO", Color3.fromRGB(180, 50, 50), function() DestroyTornado() end)
CreateSetting(TabControl, "EF Intensity Scale", "EF_Level", 1, 5, 1)
CreateSetting(TabControl, "Wander AI Speed", "WanderSpeed", 0, 100, 5)

-- DROPDOWN MENU ADDED HERE
CreateDropdown(TabPhysics, "Vortex Mode", "PhysicsMode", {"Original", "Better"})

CreateSetting(TabPhysics, "Pull Radius Mult", "RadiusMult", 0.5, 3.0, 0.1)
CreateSetting(TabPhysics, "Suck Strength Mult", "PullStrengthMult", 0.5, 5.0, 0.1)
CreateSetting(TabPhysics, "Updraft Lift Speed", "LiftSpeed", 0.5, 3.0, 0.1)
CreateSetting(TabPhysics, "Rotation Speed Mult", "RotationSpeed", 0.1, 5.0, 0.2)

CreateSetting(TabVisuals, "Transparency", "FunnelTrans", 0.1, 1.0, 0.1)
CreateSetting(TabVisuals, "Debris Amount", "DebrisDensity", 0, 500, 50)
CreateSetting(TabVisuals, "Color: Red", "Color_R", 0, 255, 15)
CreateSetting(TabVisuals, "Color: Green", "Color_G", 0, 255, 15)
CreateSetting(TabVisuals, "Color: Blue", "Color_B", 0, 255, 15)

-- =========================================================
-- 2. TORNADO GENERATION & VISUALS
-- =========================================================
local DebrisEmitter = nil

function UpdateVisuals()
	local col = Color3.fromRGB(Settings.Color_R, Settings.Color_G, Settings.Color_B)
	for _, data in ipairs(FunnelSegments) do
		data.Part.Color = col
		data.Part.Transparency = Settings.FunnelTrans
	end
	if DebrisEmitter then
		DebrisEmitter.Rate = Settings.DebrisDensity
		DebrisEmitter.Color = ColorSequence.new(col)
	end
end

function GenerateTornado()
	if TornadoActive then return end
	TornadoActive = true
	TornadoModel = Instance.new("Model", workspace)
	
	local Core = Instance.new("Part", TornadoModel)
	Core.Anchored, Core.CanCollide, Core.Transparency = true, false, 1
	Core.Position = Vector3.new(0, 5, 0)
	TornadoModel.PrimaryPart = Core
	
	local attach = Instance.new("Attachment", Core)
	DebrisEmitter = Instance.new("ParticleEmitter", attach)
	DebrisEmitter.Texture = "rbxassetid://258128463"
	DebrisEmitter.Size = NumberSequence.new({NumberSequenceKeypoint.new(0, 20), NumberSequenceKeypoint.new(1, 100)})
	DebrisEmitter.Transparency = NumberSequence.new(0.5, 1)
	DebrisEmitter.Speed = NumberRange.new(50, 150)
	DebrisEmitter.Lifetime = NumberRange.new(2, 4)
	DebrisEmitter.SpreadAngle = Vector2.new(180, 180)
	
	local stats = EF_STATS[Settings.EF_Level]
	local segments = 20 + (Settings.EF_Level * 5)
	
	task.spawn(function()
		for i = 1, segments do
			local p = Instance.new("Part")
			p.Shape, p.Anchored = Enum.PartType.Cylinder, true
			p.CanCollide, p.CanTouch, p.CanQuery = false, false, false
			p.Material = Enum.Material.SmoothPlastic
			
			local ratio = i / segments
			local width = (5 + (ratio ^ 3) * (120 * stats.Scale))
			p.Size = Vector3.new((stats.Height/segments) * 1.5, width, width)
			
			local decal = Instance.new("Decal", p)
			decal.Texture = "rbxassetid://258128463"
			decal.Transparency = 0.5
			
			p.Parent = TornadoModel
			table.insert(FunnelSegments, {Part = p, Height = i * (stats.Height/segments), Speed = 15 * (1.2 - ratio)})
			if i % 5 == 0 then task.wait() end 
		end
		UpdateVisuals()
	end)
	
	task.spawn(function()
		while TornadoActive do
			local target = Core.Position + Vector3.new(math.random(-300, 300), 0, math.random(-300, 300))
			local path = PathfindingService:CreatePath({AgentRadius = 10, AgentCanJump = false})
			path:ComputeAsync(Core.Position, target)
			if path.Status == Enum.PathStatus.Success then
				CurrentPath = path:GetWaypoints()
				CurrentWaypoint = 1
			end
			task.wait(math.random(6, 12))
		end
	end)
end

function DestroyTornado()
	TornadoActive = false
	if TornadoModel then TornadoModel:Destroy() end
	table.clear(FunnelSegments)
	CurrentPath = {}
end

-- =========================================================
-- 3. DYNAMIC PHYSICS ENGINE
-- =========================================================
RunService.Heartbeat:Connect(function(dt)
	if not TornadoActive or not TornadoModel or not TornadoModel.PrimaryPart then return end
	local t = tick()
	local stats = EF_STATS[Settings.EF_Level]
	local rootPos = TornadoModel.PrimaryPart.Position
	
	if #CurrentPath > 0 and CurrentWaypoint <= #CurrentPath then
		local wp = CurrentPath[CurrentWaypoint].Position
		local targetPos = Vector3.new(wp.X, rootPos.Y, wp.Z)
		local diff = targetPos - rootPos
		if diff.Magnitude < 5 then CurrentWaypoint += 1 else TornadoModel.PrimaryPart.Position = rootPos + (diff.Unit * Settings.WanderSpeed * dt) end
	end
	
	for _, data in ipairs(FunnelSegments) do
		local rot = CFrame.Angles(0, t * data.Speed * Settings.RotationSpeed, 0)
		local wobble = Vector3.new(math.sin(t*3 + data.Height)*3, 0, math.cos(t*3 + data.Height)*3)
		data.Part.CFrame = CFrame.new(rootPos + Vector3.new(0, data.Height, 0) + wobble) * rot * CFrame.Angles(0, 0, math.rad(90))
	end
	
	local params = OverlapParams.new()
	params.FilterType = Enum.RaycastFilterType.Exclude
	params.FilterDescendantsInstances = {TornadoModel, Player.Character}
	
	local searchRadius = stats.Radius * Settings.RadiusMult
	local partsInRadius = workspace:GetPartBoundsInRadius(rootPos, searchRadius, params)
	
	for _, p in ipairs(partsInRadius) do
		if p:IsA("BasePart") and not p.Anchored then
			local offset = p.Position - rootPos
			local currentHeight = p.Position.Y - rootPos.Y
			local horizontalDist = Vector3.new(offset.X, 0, offset.Z).Magnitude
			local forceMult = stats.Strength * Settings.PullStrengthMult
			
			-- ===============================================
			-- MODE 1: THE ORIGINAL (Geyser Spout)
			-- ===============================================
			if Settings.PhysicsMode == "Original" then
				if currentHeight > (stats.Height * 0.95) then
					p.AssemblyLinearVelocity = Vector3.new(math.random(-100, 100), 50, math.random(-100, 100)).Unit * (stats.Strength * 1.5)
					continue 
				end
				
				local tangent = Vector3.new(-offset.Z, 0, offset.X).Unit
				local inward = -Vector3.new(offset.X, 0, offset.Z).Unit
				local upward = Vector3.new(0, 1.8 * Settings.LiftSpeed, 0)
				p.AssemblyLinearVelocity = (tangent * forceMult) + (inward * (forceMult * 0.4)) + (upward * forceMult)
			
			-- ===============================================
			-- MODE 2: THE BETTER (Dynamic Distance & Random Eject)
			-- ===============================================
			elseif Settings.PhysicsMode == "Better" then
				-- Random Ejection: Parts can fly out anywhere if they are high enough
				if currentHeight > (stats.Height * 0.3) and math.random(1, 150) == 1 then
					local throwDir = Vector3.new(math.random(-100, 100), math.random(-20, 50), math.random(-100, 100)).Unit
					p.AssemblyLinearVelocity = throwDir * (stats.Strength * math.random(1.5, 3))
					continue
				end
				
				-- Distance Check
				local distPercent = math.clamp(horizontalDist / searchRadius, 0, 1)
				local liftPower = 1 - distPercent -- Closer = higher lift
				if liftPower < 0.1 then liftPower = 0.1 end -- Prevent zero lift
				
				local tangent = Vector3.new(-offset.Z, 0, offset.X).Unit
				local inward = -Vector3.new(offset.X, 0, offset.Z).Unit
				local upward = Vector3.new(0, 3 * Settings.LiftSpeed * liftPower, 0)
				
				-- Stronger inward pull for farther parts, tighter spiral for closer parts
				local suckForce = inward * (forceMult * (1.5 - distPercent))
				
				p.AssemblyLinearVelocity = (tangent * forceMult) + suckForce + (upward * forceMult)
			end
			-- ===============================================
		end
	end
end)

Features & Information

an actual tornado not any ring parts script an actual tornado (may bug sometimes and it makes you bounce sometimes, and could also lag your game)

Community Comments (4)

cezekiahjohnrocescezekiahjohnrocesMay 14, 2026

This is actually FE

CisarCisarJul 17, 2026

increible script y aparte libre, eres mi idolo

sonik_rafciosonik_rafcioAug 1, 2026

not fe

Bor4ynBor4ynAug 2, 2026

can you add an ability to control tornado?

More Scripts for Universal Scripts