careful using this module guys, but its the only module which ragdoll i like
Update!
1. Addressing the flinging away problem
Ding dong! The wicked velocity constraints is dead.
What does this mean?
In the HumanoidStarterSet scripts, I have removed the instancing of all linear and angle velocity constraints. This existed for the purpose of āwaking upā physics incase the character was stuck in a static pose that was way too still.
However, there was a better way to do this with ApplyAngularImpulse() which is a part method. So whenever a character ragdolls, they will have an angle force be applied to them (as before), but through the part itself, not a constraint. This means that there will be less instances to deal with.
As of right now it is set to a modest 50 * the forward facing vector of the UpperTorso. You can change ApplyAngularImpulse() to ApplyImpulse() if you want a vector force instead of an angular one.
This also means deactivateVelocity() is no longer needed, as these methods only fire once.
HumanoidRootPart.Anchored = true and PlatformStand = true will prevent respawning, as recognizing death requires the character to wake up. New measures have been added to prevent this.
If an anchored HumanoidRootPart is too upright (such as 0, -90, 0), it will tilt forwards via CFrame to allow gravity to wake up physics incase the prior fails. It will also unanchor, then promptly anchor them again, if itās found to be anchored in the first place.
PlatformStand will now be made false on death.
You can find these change in the ragdoll scripts themselves, for function activateVelocity()
2. More no-collide constraints and some socket setting value changes
Iām not particularly robophobic so I asked ChatGPT to add 20 total no-collide constraints I initially was too un-arsed to figure out. I donāt expect this to hit performance for the ragdolls since itās for spawning anyway. This means now that there will be less self collision on a ragdollās self, leading to more natural physics.
Do note, your own socket settings may need some adjusting if they are too unclamped.
As of right now, I have loosened up the constrains on the LowerTorso, so if you froze a humanoidRootPart in the air, the ragdoll will now go upside down.
3. Some extras
clientDiedEvent.OnServerEvent:Connect(activateVelocity) replaces activateVelocity() line on the player ragdoll script. Initially, they both existed and double fired.
Commented out some active prints.
1.1.6
-
Removed all instancing of linear and angular velocity constraints
-
Replaced their use with ApplyAngularImpulse() on the UpperTorso
-
If anchored HumanoidRootPart, it will unanchor then reanchor for a moment on death and will tilt a little forwards to help activate physics. If PlatformStand true, PlatformStand will be set to false on death. Having both be true on death will prevent your character from respawning.
-
More no-collide constraints instances to a ragdollās self
-
clientDiedEvent.OnServerEvent:Connect(activateVelocity)* replaces activateVelocity() line on the player ragdoll script.
-
Commented out some active prints.
Hey not sure if itās intended but whenever the character gets ragdoll it feels like thereās a lag spike and the game freezes
Not sure if thatās whatās actually happening but thatās how it feels
SO I have made a lightweight ragdoll system, the way to make ragdolls work with layered clothing is to not disable the waist motor. Is that how yours is for use with layered clothing? I donāt see why I would change it.
local CollectionService = game:GetService("CollectionService")
local Players = game:GetService("Players")
local RigTypes = require(script.RigTypes)
local ragdolls={}
local RAGDOLLED_TAG = "__Ragdoll_Active"
local dynamicfeet={RightAnkle = {
},
LeftAnkle = {
},}
local MAX_FRICTION_TORQUE = 10
local jointSettings = {
Neck = {
ragdollConstraintSettings = {
TwistLowerAngle = 80,
TwistUpperAngle = 60,
MaxFrictionTorque = 3 * MAX_FRICTION_TORQUE
},
},
Waist = {
ragdollConstraintSettings = {
UpperAngle = 22.5,
TwistLowerAngle = -90,
TwistUpperAngle = 11.25,
MaxFrictionTorque = 3 * MAX_FRICTION_TORQUE
},
},
LeftShoulder = {
ragdollConstraintSettings = {
UpperAngle = 180,
TwistLowerAngle = 0,-- -180,
TwistUpperAngle = 0-- 90
,MaxFrictionTorque = MAX_FRICTION_TORQUE
},
},
RightShoulder = {
ragdollConstraintSettings = {
UpperAngle = 180,
TwistLowerAngle = 0,-- -180,
TwistUpperAngle = 0-- 90
,MaxFrictionTorque = MAX_FRICTION_TORQUE
},
},
RightElbow = {
ragdollConstraintSettings = {
UpperAngle = 11.25,
TwistLowerAngle = 0,
TwistUpperAngle = 170
,MaxFrictionTorque = MAX_FRICTION_TORQUE
},
},
LeftElbow = {
ragdollConstraintSettings = {
UpperAngle = 11.25,
TwistLowerAngle = 0,
TwistUpperAngle = 170,MaxFrictionTorque = MAX_FRICTION_TORQUE
},
},
LeftWrist = {
ragdollConstraintSettings = {
UpperAngle = 11.25,
TwistLowerAngle = -80,
TwistUpperAngle = 80,MaxFrictionTorque = MAX_FRICTION_TORQUE
},
},
RightWrist = {
ragdollConstraintSettings = {
UpperAngle = 11.25,
TwistLowerAngle = -80,
TwistUpperAngle = 80,MaxFrictionTorque = MAX_FRICTION_TORQUE
},
},
RightHip = {
ragdollConstraintSettings = {
UpperAngle = 22.5,
TwistLowerAngle = -11.25,
TwistUpperAngle = 135,
MaxFrictionTorque = 3 * MAX_FRICTION_TORQUE
},
},
LeftHip = {
ragdollConstraintSettings = {
UpperAngle = 22.5,
TwistLowerAngle = -11.25,
TwistUpperAngle = 135,
MaxFrictionTorque = 3 * MAX_FRICTION_TORQUE
},
},
LeftKnee = {
ragdollConstraintSettings = {
UpperAngle = 0,
TwistLowerAngle = -170,
TwistUpperAngle = 0
,MaxFrictionTorque = MAX_FRICTION_TORQUE
},
},
RightKnee = {
ragdollConstraintSettings = {
UpperAngle = 0,
TwistLowerAngle = -170,
TwistUpperAngle = 0
},
},
RightAnkle = {
ragdollConstraintSettings = {
UpperAngle = 22.5,
TwistLowerAngle = -45,
TwistUpperAngle = 11.25
},
},
LeftAnkle = {
ragdollConstraintSettings = {
UpperAngle = 22.5,
TwistLowerAngle = -45,
TwistUpperAngle = 11.25
},
},
}
local R15Bodyparts={
["Head"] = "Neck",
["LeftFoot"] = "LeftAnkle",
["LeftHand"] = "LeftWrist",
["LeftLowerArm"] = "LeftElbow",
["LeftLowerLeg"] = "LeftKnee",
["LeftUpperArm"] = "LeftShoulder",
["LeftUpperLeg"] = "LeftHip",
["LowerTorso"] = "Root",
["RightFoot"] = "RightAnkle",
["RightHand"] = "RightWrist",
["RightLowerArm"] = "RightElbow",
["RightLowerLeg"] = "RightKnee",
["RightUpperArm"] = "RightShoulder",
["RightUpperLeg"] = "RightHip",
["UpperTorso"] = "Waist"
}
local function unragdollnodata(model,humanoid)
if CollectionService:HasTag(model, RAGDOLLED_TAG) then
model.PrimaryPart.Massless=false
if not humanoid then
humanoid=model:FindFirstChildOfClass("Humanoid")
end
model.PrimaryPart.Anchored=true
humanoid.PlatformStand=false
local player=game.Players:GetPlayerFromCharacter(model)
local data={Enable={},Delete={}}
for i,key in R15Bodyparts do
if model:FindFirstChild(i) then
model[i].CanCollide=false
model[i][key].Enabled=true
model[i].Anchored=false
table.insert(data.Enable,model[i][key])
else
print("Cannot find "..i)
end
end
model.PrimaryPart.CanCollide=true
local attachments = RigTypes.getAttachments(model, humanoid.RigType)
for name, objects in pairs(attachments) do
local parent = model:FindFirstChild(name)
if parent then
local key= name.."RagdollBallSocketConstraint"
local motor=parent:FindFirstChildOfClass("Motor6D")
if motor and jointSettings[motor.Name] then
motor.Enabled=true
end
local ballsocket=parent:FindFirstChild(key)
if ballsocket then
ballsocket:Destroy()
end
end
end
local parts = RigTypes.getNoCollisions(model, humanoid.RigType)
for i, objects in pairs(parts) do
local constraint = objects[1]:FindFirstChild(objects[1].Name.."BallSocket"..i)
if constraint then
constraint:Destroy()
end
end
local clones={}
--for i,v in model:GetChildren() do
-- if v:IsA("Accessory") and v:FindFirstChild("Handle") and v.Handle:FindFirstChildOfClass("WrapLayer") then
-- table.insert(clones,v:Clone())
-- v:Destroy()
-- end
--end
--task.delay(1,function()
--for i,v in clones do
-- humanoid:AddAccessory(v)
--end
model.PrimaryPart.Anchored=false
humanoid.EvaluateStateMachine=true
humanoid.PlatformStand=false
humanoid:ChangeState(Enum.HumanoidStateType.GettingUp)
model:RemoveTag(RAGDOLLED_TAG)
end
end
function ragdolls.unragdoll(model,humanoid,data)
if data==nil then
unragdollnodata(model,humanoid)
else
if CollectionService:HasTag(model, RAGDOLLED_TAG) then
CollectionService:RemoveTag(model, RAGDOLLED_TAG)
model.PrimaryPart.Massless=false
model.PrimaryPart.CanCollide=true
model.PrimaryPart.Anchored=true
if model:FindFirstChild("HumanoidRootPart") then
model.HumanoidRootPart.CanCollide=true
end
if not humanoid then
humanoid=model:FindFirstChildOfClass("Humanoid")
end
for i,v in data.Delete do
v:Destroy()
end
for i,v in data.Enable do
v.Enabled=true
end
humanoid:BuildRigFromAttachments()
end
local clones={}
for i,v in model:GetChildren() do
if v:IsA("Accessory") and v:FindFirstChild("Handle") and v.Handle:FindFirstChildOfClass("WrapLayer") then
table.insert(clones,v:Clone())
v:Destroy()
end
end
--task.delay(1,function()
for i,v in clones do
humanoid:AddAccessory(v)
end
humanoid.EvaluateStateMachine=true
humanoid.PlatformStand=false
--humanoid:ChangeState(Enum.HumanoidStateType.GettingUp)
model.PrimaryPart.Anchored=false
--task.wait(.3)
humanoid:ChangeState(Enum.HumanoidStateType.GettingUp)
-- humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
--end)
end
end
function ragdolls.ragdoll(model, humanoid,duration)
--assert(humanoid:IsDescendantOf(model))
if CollectionService:HasTag(model, RAGDOLLED_TAG) then
return
end
if not humanoid then
humanoid=model:FindFirstChildOfClass("Humanoid")
end
if humanoid then
CollectionService:AddTag(model, RAGDOLLED_TAG)
model.PrimaryPart.Massless=true
-- Turn into loose body:
--if humanoid then
--humanoid:ChangeState(Enum.HumanoidStateType.Physics)
humanoid.PlatformStand=true
local player=game.Players:GetPlayerFromCharacter(model)
local data={Enable={},Delete={}}
for i,key in R15Bodyparts do
if model:FindFirstChild(i) then
model[i].CanCollide=true
model[i].Anchored=true
model[i][key].Enabled=false
table.insert(data.Enable,model[i][key])
else
--print("Cannot find "..i)
end
end
-- Instantiate BallSocketConstraints:
local attachments = RigTypes.getAttachments(model, humanoid.RigType)
local velocities={}
for name, objects in pairs(attachments) do
local parent = model:FindFirstChild(name)
if parent then
local constraint = Instance.new("BallSocketConstraint")
constraint.Name = name.."RagdollBallSocketConstraint"
constraint.Attachment0 = objects.attachment0
constraint.Attachment1 = objects.attachment1
constraint.LimitsEnabled = true
constraint.UpperAngle = objects.limits.UpperAngle
constraint.TwistLimitsEnabled = true
constraint.TwistLowerAngle = objects.limits.TwistLowerAngle
constraint.TwistUpperAngle = objects.limits.TwistUpperAngle
constraint.Parent = parent
local motor=parent:FindFirstChildOfClass("Motor6D")
if motor and jointSettings[motor.Name] then
for t,o in jointSettings[motor.Name].ragdollConstraintSettings do
constraint[t]=o
end
local c=Instance.new("RopeConstraint")
c.Length=.15
c.Name=name.."RopeConstraint"
c.Restitution=1
c.Visible=false
c.WinchForce=math.huge
c.WinchSpeed=math.huge
c.WinchEnabled=true
-- c.WinchTarget=.25
c.WinchResponsiveness=math.huge
c.Attachment0= objects.attachment0
c.Attachment1= objects.attachment1
c.Parent=parent
c.WinchTarget=math.max(.15,(motor.C0.Position-motor.C1.Position).Magnitude)
table.insert(data.Delete,c)
table.insert(data.Enable,motor)
motor.Enabled=false
constraint.Restitution=0.05
end
table.insert(velocities,parent)
table.insert(data.Delete,constraint)
end
end
model.UpperTorso.Waist.Enabled=true--Layered Clothing Fix
-- Instantiate NoCollisionConstraints:
local parts = RigTypes.getNoCollisions(model, humanoid.RigType)
for i, objects in pairs(parts) do
local constraint = objects[1]:FindFirstChild(objects[1].Name.."BallSocket"..i) or Instance.new("NoCollisionConstraint")
constraint.Name = objects[1].Name.."BallSocket"..i
constraint.Part0 = objects[1]
constraint.Part1 = objects[2]
constraint.Parent = objects[1]
table.insert(data.Delete,constraint)
end
--model
for t,o in jointSettings do
if o.ragdollConstraintSettings.MaxFrictionTorque==nil then
o.ragdollConstraintSettings.MaxFrictionTorque = MAX_FRICTION_TORQUE
end
end
-- Destroy all regular joints:
for _, motor in pairs(model:GetDescendants()) do
if motor:IsA("Motor6D") then
table.insert(velocities,motor.Parent)
end
end
for i,key in R15Bodyparts do
if model:FindFirstChild(i) then
model[i].CanCollide=true
model[i].Anchored=false
model[i].AssemblyLinearVelocity=Vector3.new(0,0,0)--vec--Vector3.new(0,0,0)
--model[i].AssemblyAngularVelocity=Vector3.new(0,0,0)
if player then
pcall(function() model[i]:SetNetworkOwner(player) end)
end
else
print("Cannot find "..i)
end
end
local function weldmotor(Root1,Root2)
local w=Instance.new("Motor6D")
w.Part0,w.Part1 = Root1,Root2
w.C0 = Root2.CFrame:toObjectSpace(Root1.CFrame):inverse()
w.Parent = Root1
w.Name=Root2.Name.."Joint"
return w
end
table.insert(data.Delete,weldmotor(model.HumanoidRootPart,model:FindFirstChild("UpperTorso") or model:FindFirstChild("Head")))
if game.Players:GetPlayerFromCharacter(model) then
task.spawn(function()
local vec=Vector3.new(0,0,0)
local VelocityConstraint=40
local function constrainsum(v)
local x,y,z=v.X,v.Y,v.Z
if x>VelocityConstraint then
x=VelocityConstraint
elseif x<-VelocityConstraint then
x=-VelocityConstraint
end
if y>VelocityConstraint then
y=VelocityConstraint
elseif y<-VelocityConstraint then
y=-VelocityConstraint
end
if z>VelocityConstraint then
z=VelocityConstraint
elseif z<-VelocityConstraint then
z=-VelocityConstraint
end
return Vector3.new(x,y,z)
end
while CollectionService:HasTag(model, RAGDOLLED_TAG) do --lose velocity
for i,v in velocities do
v.AssemblyLinearVelocity=constrainsum(v.AssemblyLinearVelocity)--vec--Vector3.new(0,0,0)
v.AssemblyAngularVelocity=constrainsum(v.AssemblyAngularVelocity)
--v.AssemblyLinearVelocity
--v.AssemblyAngularVelocity*=.95
end
task.wait(.08)
end
end)
end
humanoid.EvaluateStateMachine=false
if model:FindFirstChild("HumanoidRootPart") then
model.HumanoidRootPart.CanCollide=false
end
return data
end
end
return ragdolls
I do have some quips with yours. It seems a bit complicated and invasive to destroy the characters motors when they can be enabled or disabled, in addition there is many lines of repeating code illustrated by this image.
I think it would benefit by iterating through a table to and getting the children of those objects rather than doing all those separate loops that also appears to disable and destroy and motor inside those parts, which could cause bugs.
local R15Bodyparts={
["Head"] = "Neck",
["LeftFoot"] = "LeftAnkle",
["LeftHand"] = "LeftWrist",
["LeftLowerArm"] = "LeftElbow",
["LeftLowerLeg"] = "LeftKnee",
["LeftUpperArm"] = "LeftShoulder",
["LeftUpperLeg"] = "LeftHip",
["LowerTorso"] = "Root",
["RightFoot"] = "RightAnkle",
["RightHand"] = "RightWrist",
["RightLowerArm"] = "RightElbow",
["RightLowerLeg"] = "RightKnee",
["RightUpperArm"] = "RightShoulder",
["RightUpperLeg"] = "RightHip",
["UpperTorso"] = "Waist"
}
Update! Weāre at 1.2.0 now.
1. Smooth ragdolling again!

I like cooking with olive oil. Thus I cooked so hard that I made the ragdolls slippery smooth againā¦like hot olive oil.
With SetNetworkOwnership() trickery, I was able to fix the freezing effect on clientside views when the ragdoll begins. SetNetworkOwnership() is given to the server at the start of player death, and then given back to the player before the anchoring of ragdolls. Do note, you cannot transfer network ownership on anchored parts nor ones via clientside.
2. Better instance treatments
Taking account into @Magus_ArtStudiosās suggestion, it was a good idea to not delete Motor6D joints indeed. I couldāve disabled it (Why I didnāt know this, I donāt know).
I hope this gives people who make non-dying ragdoll modifications a better time.
3. Simpler function ragdollMe()
Continuing (kinda) with another suggestion by @Magus_ArtStudios, for the ragdoll initiation:
Iāve changed how low definition ragdolls have their parts be selected for eligibility. It should simply be in a table with the rigged partās name on it, making it very scalable.
For regular ragdoll operations, the new ragdollMe loop accesses a character:GetChildren() instance if they are a BasePart and arenāt a HumanoidRootPart.
Both then take its Motor6D and send it to a new function called partProcessor(), where the parts get modified, and their Motor6Ds disabled (Not destroyed like before).
4. Some extras
Changed pair loops to ipair loops when necessary for performance.
More socket setting changes, since I made it waaay too micro jittery.
HumanoidRootPart no longer has a socket effect (No point in doing so and wastes physics calculation)
1.2.0
- SetNetworkOwnership() is given to the server at the start of player death, and then given back to the player before the anchoring of ragdolls. This ensures smooth ragdolls on frame.
- Motor6Ds are now preserved and disabled instead of being destroyed.
- ragdollMe() now uses a simpler loop and low definition ragdoll parts can now be selected via table
- Changed pair loops to ipair loops when necessary for performance.
- More socket setting changes, since I made it waaay too micro jittery.
- HumanoidRootPart no longer has a socket effect (No point in doing so and wastes physics calculation)
Hey not sure if itās intended but whenever the character gets ragdoll it feels like thereās a lag spike and the game freezes
I suspected it was network problems. It was indeed network problems. At some point Roblox mustāve updated the physics handling to where transfer of physics ownership was no longer automatic. The freezing was because of the network transfer of all the physics data, but it was only visual due to it affecting the clientside only.
SO I have made a lightweight ragdoll system, the way to make ragdolls work with layered clothing is to not disable the waist motor. Is that how yours is for use with layered clothing? I donāt see why I would change it.
So the reason why I set it up that way was back when this was released, layered clothing would angle itself in a weird way, and taking it on and off again would repair the visual anomaly. I havenāt checked up on how time has treated the solution though.
Ooh I didnāt realize taking it on and off again would fix the layered clothing. That is much better than sacrificing the waist ball joint. Maybe enabling and disabling the cage mesh would be more performant. I will be modifying mine and ill try toggling the cage mesh first.
please fix, add some check to see if a character exists and if an uppertorso exist in that function
also im not so sure of it but i think this is a memory leak, why not just put it outside the Died event since the player parameter is passed from the remotevent anyways ?

Thanks for letting me know. I have published a quick fix.
1.2.1
- Added a FindFirstChild check on activateVelocity for an UpperTorso.
- clientDiedEvent is now a connected to a variable and utilizes an anonymous function to activate ragdollMe() then activateVelocity(). It has been placed outside the humanoid.Died() connection.
- Changed tool removal loop to a simpler backpack:ClearAllChildren()
well you did fix the memory leak, but you also broke the module
you can fix it by verifying the player with this line of code

but this way is still inefficient, why connect like 30 events if there are 30 players if you can just do it once for everyone
i worded my reply badly, i meant outside the Died in the global scope, not directly outside
you did it right in the NPC script

this is the end result, pass in the character from the client also cause what if its been replaced/destroyed by the time it reached the server

Whoops, pardon the oversight. I tested on singleplayer instead of a 2 player local server so that slipped past me. Iāve passed the local player through the connection now.
As for the connection, the reason I set it up that way is because of the structure in which the functions were to be fired. I specifically wanted ragdollMe() and activateVelocity() to run in that order to avoid any asyncād race conditions. If you wish to de-nest it and set it globally, thatās fine. Itās open source code.
I also would rather not trust the character details coming in from the client in the connection. If someone does modify the character for a clientside only feature, they know what to do with their code more than me.