A-Chassis Bike Commission
Modified **A-Chassis 1.7.2** for a Roblox motorcycle commission, fixing head accessories not attaching properly to animation rigs. Developed a universal arm & leg animation system compatible with various Roblox avatar packages supporting R6 & R15. Also implemented a safe dismount system to prevent physics glitches, unwanted launching, and collisions when exiting the motorcycle.

Head Accessory Fix
Modified the A-Chassis 1.7.2 animation plugin to fix head accessories not properly attaching to the rider's animation rig. Ensured accessories remained correctly positioned and moved with the character during riding animations.


PUBLIC FIX SCRIPT
This is to be in placed of the FEAnims script, which is inside of the local script plugin, parented by the "Anims" RemoteEvent.
--[[
_____ _ _
/\ / ____| | (_)
/ \ ______| | | |__ __ _ ___ ___ _ ___
/ /\ \______| | | '_ \ / _` / __/ __| / __|
/ ____ \ | |____| | | | (_| \__ \__ \ \__ \
/_/ \_\ \_____|_| |_|\__,_|___/___/_|___/
Version 1.7M
Authors:
pointclouded ph.n nathanisalive a_person730
LuaInt vanilla01 au.to.
detocoyote mischarfess s.wick
Edited By: lceyDex
Last Edited: 10/29/2026
Description: Fixed R6 & R15 head accessories
--]]
task.wait(1)
local bike = script.Parent.Parent
local F = {}
local HeadState = {}
local ACCESSORY_TRANSPARENCY_ATTR = "_BikeAccessoryOldTransparency"
local HEAD_WELD_NAME = "_BikeRealHeadWeld"
-- APPEARANCE PATCH (working-rig edition)
-- These switches affect only the visual representation of R15 players.
-- No new IK, Motor6D, torso offsets, or chassis changes are made.
-- Uniform rig fit keeps each imported body mesh's original aspect ratio,
-- but matches its LENGTH to the known-working motorcycle's animation rig.
-- Scaling to the avatar's exact sizes without adjusting the rig causes gaps.
-- Setting this false restores the old fixed-size (more distorted) behavior.
local R15_UNIFORM_RIG_FIT = true
-- 1 = preserve mesh proportions; 0 = legacy template width/depth.
-- The length (Y) always stays equal to the working rig when enabled.
local R15_SHAPE_PRESERVATION = 1.0
-- V7: prevent non-standard R15 arm packages from becoming huge on the bike.
-- Keep every arm segment's original animation length. Fit its thickness
-- using the scale of the WHOLE arm, not the length of that one segment.
-- For normal R15 avatars the original V5 fit is retained.
local R15_SMART_ARM_FIT = true
local R15_ARM_LENGTH_SCALE_ALLOWANCE = 1.10
local R15_ARM_MAX_RIG_THICKNESS = 0.92
-- V8: the original rig has FIXED thigh, shin and foot lengths.
-- Some body packages have much shorter leg MeshParts, so V5/V7's
-- per-segment scale factor made their thickness several times too large.
-- Keep the original lengths, but use one ratio for the ENTIRE leg when
-- deciding the visual width/depth. Neither the welds nor poses are changed.
local R15_SMART_LEG_FIT = true
local R15_LEG_LENGTH_SCALE_ALLOWANCE = 1.05
local R15_LEG_MAX_RIG_THICKNESS = 0.82
local R15_FOOT_MAX_RIG_THICKNESS = 0.93
local R15_COPY_BODY_ACCESSORIES = true
local R15_COPY_CAGE_COMPONENTS = true
local R15_REAL_TRANSPARENCY_ATTR = "_BikeOldR15Transparency"
local COPIED_ACCESSORY_ATTR = "_BikeCopiedR15Accessory"
-- Moving dismount protection.
-- Stationary dismounts are already behaving correctly, so this only
-- activates when the motorcycle still has meaningful horizontal speed.
local MOVING_DISMOUNT_SPEED = 3
local DISMOUNT_COLLISION_MIN_TIME = 0.30
local DISMOUNT_COLLISION_MAX_TIME = 0.90
local DISMOUNT_SAFE_DISTANCE = 7
local DISMOUNT_FOLDER_NAME = "_BikeDismountNoCollision"
-- Use the rider's actual body hierarchy as the source of truth. Some avatar
-- packages/imported characters can report a RigType that does not match the
-- body parts present in the model.
local function getAnimationRigType(character)
if character
and character:FindFirstChild("UpperTorso")
and character:FindFirstChild("LowerTorso")
and character:FindFirstChild("RightUpperArm")
and character:FindFirstChild("LeftUpperArm")
then
return Enum.HumanoidRigType.R15
end
if character
and character:FindFirstChild("Torso")
and character:FindFirstChild("Right Arm")
and character:FindFirstChild("Left Arm")
then
return Enum.HumanoidRigType.R6
end
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
return humanoid and humanoid.RigType or Enum.HumanoidRigType.R6
end
bike.Misc.Anims.R15.RightArm.UpperArm.Parts.RightUpperArm.Parent =
bike.Misc.Anims.R15
bike.Misc.Anims.R15.RightArm.LowerArm.Parts.RightLowerArm.Parent =
bike.Misc.Anims.R15
bike.Misc.Anims.R15.RightArm.Hand.Parts.RightHand.Parent =
bike.Misc.Anims.R15
bike.Misc.Anims.R15.RightLeg.UpperLeg.Parts.RightUpperLeg.Parent =
bike.Misc.Anims.R15
bike.Misc.Anims.R15.RightLeg.LowerLeg.Parts.RightLowerLeg.Parent =
bike.Misc.Anims.R15
bike.Misc.Anims.R15.RightLeg.Foot.Parts.RightFoot.Parent =
bike.Misc.Anims.R15
bike.Misc.Anims.R15.LeftArm.UpperArm.Parts.LeftUpperArm.Parent =
bike.Misc.Anims.R15
bike.Misc.Anims.R15.LeftArm.LowerArm.Parts.LeftLowerArm.Parent =
bike.Misc.Anims.R15
bike.Misc.Anims.R15.LeftArm.Hand.Parts.LeftHand.Parent =
bike.Misc.Anims.R15
bike.Misc.Anims.R15.LeftLeg.UpperLeg.Parts.LeftUpperLeg.Parent =
bike.Misc.Anims.R15
bike.Misc.Anims.R15.LeftLeg.LowerLeg.Parts.LeftLowerLeg.Parent =
bike.Misc.Anims.R15
bike.Misc.Anims.R15.LeftLeg.Foot.Parts.LeftFoot.Parent =
bike.Misc.Anims.R15
bike.Misc.Anims.R15.Torso.LowerTorso.Parts.LowerTorso.Parent =
bike.Misc.Anims.R15
bike.Misc.Anims.R15.Torso.UpperTorso.Parts.UpperTorso.Parent =
bike.Misc.Anims.R15
-- Keep NewHead physically attached to the animation rig,
-- but move it where the original FEAnims expects it.
bike.Misc.Anims.R15.Torso.Head.Parts.NewHead.Parent =
bike.Misc.Anims.R15
--============================================================
-- R15 BODY APPEARANCE TEMPLATES
--============================================================
local R15_BODY_PART_NAMES = {
"RightUpperArm",
"RightLowerArm",
"RightHand",
"RightUpperLeg",
"RightLowerLeg",
"RightFoot",
"LeftUpperArm",
"LeftLowerArm",
"LeftHand",
"LeftUpperLeg",
"LeftLowerLeg",
"LeftFoot",
"LowerTorso",
"UpperTorso"
}
local R15OriginalAppearance = {}
local R15BodyUniformScales = {}
local COPIED_BODY_APPEARANCE_ATTR = "_BikeCopiedBodyAppearance"
for _, name in ipairs(R15_BODY_PART_NAMES) do
local part = bike.Misc.Anims.R15:FindFirstChild(name)
if part and part:IsA("MeshPart") then
local template = part:Clone()
template.Parent = nil
R15OriginalAppearance[name] = {
Mesh = template,
Size = part.Size,
Material = part.Material,
MaterialVariant = part.MaterialVariant,
Reflectance = part.Reflectance
}
end
end
--============================================================
-- HEAD HELPERS
--============================================================
local function findNeck(character)
local head =
character:FindFirstChild("Head")
if not head then
return nil
end
for _, object in ipairs(
character:GetDescendants()
) do
if object:IsA("Motor6D")
and object.Name == "Neck"
and object.Part1 == head
then
return object
end
end
return nil
end
local function getFakeHead(rigType)
if rigType ==
Enum.HumanoidRigType.R6
then
return
bike.Misc.Anims.R6.Head.Parts.NewHead
end
return
bike.Misc.Anims.R15.NewHead
end
-- accessories refactored
local function isHeadAccessory(accessory, head)
local handle =
accessory:FindFirstChild("Handle")
if not handle
or not handle:IsA("BasePart")
then
return false
end
local accessoryWeld =
handle:FindFirstChild(
"AccessoryWeld"
)
if accessoryWeld
and accessoryWeld.Part1 == head
then
return true
end
-- Attachment fallback for newer accessories.
for _, object in ipairs(
handle:GetChildren()
) do
if object:IsA("Attachment") then
local matching =
head:FindFirstChild(
object.Name
)
if matching
and matching:IsA("Attachment")
then
return true
end
end
end
return false
end
local function hideNonHeadAccessories(character)
local head =
character:FindFirstChild("Head")
if not head then
return
end
for _, accessory in ipairs(
character:GetChildren()
) do
if accessory:IsA("Accessory")
and not isHeadAccessory(
accessory,
head
)
then
for _, object in ipairs(
accessory:GetDescendants()
) do
if object:IsA("BasePart") then
if object:GetAttribute(
ACCESSORY_TRANSPARENCY_ATTR
) == nil then
object:SetAttribute(
ACCESSORY_TRANSPARENCY_ATTR,
object.Transparency
)
end
object.Transparency = 1
end
end
end
end
end
local function restoreAccessories(character)
for _, accessory in ipairs(
character:GetChildren()
) do
if accessory:IsA("Accessory") then
for _, object in ipairs(
accessory:GetDescendants()
) do
if object:IsA("BasePart") then
local oldTransparency =
object:GetAttribute(
ACCESSORY_TRANSPARENCY_ATTR
)
if oldTransparency ~= nil then
object.Transparency =
oldTransparency
object:SetAttribute(
ACCESSORY_TRANSPARENCY_ATTR,
nil
)
end
end
end
end
end
end
--============================================================
-- ATTACH PLAYER'S REAL HEAD TO NEWHEAD
--============================================================
local function attachRealHead(
character,
rigType
)
local humanoid =
character:FindFirstChildOfClass(
"Humanoid"
)
local head =
character:FindFirstChild(
"Head"
)
local target =
getFakeHead(
rigType
)
if not humanoid
or not head
or not target
then
warn(
"[Bike Anims] Missing Humanoid, Head, or NewHead"
)
return
end
--------------------------------------------------------
-- REMOVE STALE BIKE WELD
--------------------------------------------------------
local oldBikeWeld =
head:FindFirstChild(
HEAD_WELD_NAME
)
if oldBikeWeld then
oldBikeWeld:Destroy()
end
--------------------------------------------------------
-- FIND REAL PLAYER NECK
--------------------------------------------------------
local neck =
findNeck(character)
--------------------------------------------------------
-- SAVE ORIGINAL STATE
--------------------------------------------------------
HeadState[character] = {
Neck =
neck,
NeckPart1 =
neck and neck.Part1 or nil,
NeckC0 =
neck and neck.C0 or nil,
NeckC1 =
neck and neck.C1 or nil,
NeckTransform =
neck and neck.Transform or nil,
NeckEnabled =
neck and neck.Enabled or nil,
RequiresNeck =
humanoid.RequiresNeck,
HeadTransparency =
head.Transparency,
HeadCanCollide =
head.CanCollide,
HeadCanTouch =
head.CanTouch,
HeadCanQuery =
head.CanQuery,
HeadMassless =
head.Massless
}
--------------------------------------------------------
-- FULLY DETACH REAL HEAD FROM PLAYER TORSO
--------------------------------------------------------
humanoid.RequiresNeck =
false
if neck then
neck.Enabled =
false
neck.Part1 =
nil
end
--------------------------------------------------------
-- SAFE PHYSICS
--------------------------------------------------------
head.Anchored =
false
head.CanCollide =
false
head.CanTouch =
false
head.CanQuery =
false
head.Massless =
true
target.CanCollide =
false
target.CanTouch =
false
target.CanQuery =
false
target.Massless =
true
--------------------------------------------------------
-- PUT REAL HEAD EXACTLY ON PRESET HEAD
--------------------------------------------------------
head.CFrame =
target.CFrame
--------------------------------------------------------
-- WELD REAL HEAD DIRECTLY TO NEWHEAD
--------------------------------------------------------
local weld =
Instance.new("Weld")
weld.Name =
HEAD_WELD_NAME
weld.Part0 =
target
weld.Part1 =
head
weld.C0 =
CFrame.new()
weld.C1 =
CFrame.new()
weld.Parent =
head
HeadState[character].BikeWeld =
weld
--------------------------------------------------------
-- PLAYER'S REAL HEAD IS THE VISIBLE HEAD
--------------------------------------------------------
head.Transparency =
HeadState[character].HeadTransparency
target.Transparency =
1
end
--============================================================
-- MOVING DISMOUNT COLLISION PROTECTION
--============================================================
local function getHorizontalBikeSpeed()
local velocity = bike.DriveSeat.AssemblyLinearVelocity
return Vector3.new(
velocity.X,
0,
velocity.Z
).Magnitude
end
local function createDismountNoCollision(character)
local oldFolder =
character:FindFirstChild(
DISMOUNT_FOLDER_NAME
)
if oldFolder then
oldFolder:Destroy()
end
local folder = Instance.new("Folder")
folder.Name = DISMOUNT_FOLDER_NAME
folder.Parent = character
local characterParts = {}
local bikeParts = {}
-- Include character body parts AND accessory handles.
for _, object in ipairs(character:GetDescendants()) do
if object:IsA("BasePart") then
table.insert(characterParts, object)
end
end
-- Only motorcycle parts capable of producing a collision.
for _, object in ipairs(bike:GetDescendants()) do
if object:IsA("BasePart")
and object.CanCollide
then
table.insert(bikeParts, object)
end
end
-- Prevent the rider from colliding with the motorcycle during
-- the brief moving-dismount separation period.
for _, characterPart in ipairs(characterParts) do
for _, bikePart in ipairs(bikeParts) do
local noCollision =
Instance.new("NoCollisionConstraint")
noCollision.Name =
"_BikeDismountNC"
noCollision.Part0 = characterPart
noCollision.Part1 = bikePart
noCollision.Parent = folder
end
end
return folder
end
local function finishMovingDismountPhysics(
character,
state,
noCollisionFolder
)
task.spawn(function()
local root =
character:FindFirstChild(
"HumanoidRootPart"
)
local startTime = os.clock()
while character.Parent do
task.wait()
local elapsed =
os.clock() - startTime
local farEnough = false
if root
and root.Parent
and bike.DriveSeat.Parent
then
farEnough =
(root.Position - bike.DriveSeat.Position).Magnitude
>= DISMOUNT_SAFE_DISTANCE
end
if elapsed >= DISMOUNT_COLLISION_MIN_TIME
and farEnough
then
break
end
if elapsed >= DISMOUNT_COLLISION_MAX_TIME then
break
end
end
-- Restore the head's original physics only after the player
-- has cleared the moving motorcycle.
local head =
character:FindFirstChild("Head")
if head then
head.CanCollide = state.HeadCanCollide
head.CanTouch = state.HeadCanTouch
head.CanQuery = state.HeadCanQuery
head.Massless = state.HeadMassless
end
if noCollisionFolder
and noCollisionFolder.Parent
then
noCollisionFolder:Destroy()
end
end)
end
--============================================================
-- RESTORE PLAYER HEAD AFTER EXIT
--============================================================
local function restoreRealHead(character)
local state =
HeadState[character]
if not state then
return
end
local humanoid =
character:FindFirstChildOfClass(
"Humanoid"
)
local head =
character:FindFirstChild(
"Head"
)
local neck =
state.Neck
local movingDismount =
getHorizontalBikeSpeed()
> MOVING_DISMOUNT_SPEED
-- Build the no-collision barrier BEFORE removing the bike weld.
-- This prevents even one physics frame where the rider is loose
-- while still colliding with the motorcycle.
local noCollisionFolder = nil
if movingDismount then
noCollisionFolder =
createDismountNoCollision(character)
end
if humanoid then
humanoid.RequiresNeck = false
end
--------------------------------------------------------
-- REMOVE BIKE HEAD WELD
--------------------------------------------------------
if state.BikeWeld
and state.BikeWeld.Parent
then
state.BikeWeld:Destroy()
end
--------------------------------------------------------
-- PLACE HEAD BACK WHERE NORMAL NECK EXPECTS IT
--------------------------------------------------------
if head
and neck
and neck.Parent
and neck.Part0
then
head.CFrame =
neck.Part0.CFrame
* state.NeckC0
* state.NeckTransform
* state.NeckC1:Inverse()
neck.C0 = state.NeckC0
neck.C1 = state.NeckC1
neck.Transform = state.NeckTransform
neck.Part1 =
state.NeckPart1
or head
neck.Enabled =
state.NeckEnabled
end
--------------------------------------------------------
-- RESTORE HEAD PHYSICS
--------------------------------------------------------
if head then
head.Transparency =
state.HeadTransparency
if movingDismount then
-- Initialize is also deliberately keeping the rider massless
-- during this period. FEAnims must not undo that early.
head.CanCollide = false
head.CanTouch = false
head.CanQuery = false
head.Massless = true
else
-- Leave the already-good stationary dismount unchanged.
head.CanCollide = state.HeadCanCollide
head.CanTouch = state.HeadCanTouch
head.CanQuery = state.HeadCanQuery
head.Massless = state.HeadMassless
end
end
if humanoid then
humanoid.RequiresNeck =
state.RequiresNeck
end
HeadState[character] = nil
if movingDismount then
finishMovingDismountPhysics(
character,
state,
noCollisionFolder
)
end
end
--============================================================
-- BODY APPEARANCE
--============================================================
local function applyR6SkinTone(C)
if C:FindFirstChild("Torso") then
bike.Misc.Anims.R6.Torso.Parts.Torso.Color = C.Torso.Color
end
if C:FindFirstChild("Right Arm") then
bike.Misc.Anims.R6.RightArm.Parts["Right Arm"].Color = C["Right Arm"].Color
end
if C:FindFirstChild("Left Arm") then
bike.Misc.Anims.R6.LeftArm.Parts["Left Arm"].Color = C["Left Arm"].Color
end
if C:FindFirstChild("Right Leg") then
bike.Misc.Anims.R6.RightLeg.Parts["Right Leg"].Color = C["Right Leg"].Color
end
if C:FindFirstChild("Left Leg") then
bike.Misc.Anims.R6.LeftLeg.Parts["Left Leg"].Color = C["Left Leg"].Color
end
end
-- Classic Roblox body packages (Woman, Robloxian 2.0, etc.) are represented
-- by CharacterMesh objects on six-part avatars. Copy the matching mesh to the
-- fake animated limb so the bike does not turn those avatars back into blocks.
local function copyR6CharacterMeshes(C)
local targets = {
[Enum.BodyPart.Torso] = bike.Misc.Anims.R6.Torso.Parts,
[Enum.BodyPart.RightArm] = bike.Misc.Anims.R6.RightArm.Parts,
[Enum.BodyPart.LeftArm] = bike.Misc.Anims.R6.LeftArm.Parts,
[Enum.BodyPart.RightLeg] = bike.Misc.Anims.R6.RightLeg.Parts,
[Enum.BodyPart.LeftLeg] = bike.Misc.Anims.R6.LeftLeg.Parts
}
for _, object in ipairs(C:GetChildren()) do
if object:IsA("CharacterMesh") then
local target = targets[object.BodyPart]
if target then
object:Clone().Parent = target
end
end
end
end
local function clearCopiedR15Visuals(part)
for _, child in ipairs(part:GetChildren()) do
if child:GetAttribute(COPIED_BODY_APPEARANCE_ATTR) then
child:Destroy()
end
end
end
local function getWholeArmScale(character, side)
-- Compute one scale from the total shoulder-to-fingertip length.
-- This prevents very short UpperArm or LowerArm meshes from being
-- inflated independently just to match the old mannequin's joints.
local sourceLength, rigLength = 0, 0
for _, suffix in ipairs({"UpperArm", "LowerArm", "Hand"}) do
local name = side .. suffix
local real = character:FindFirstChild(name)
local rigPart = R15OriginalAppearance[name]
if not real or not real:IsA("MeshPart") or not rigPart then
return nil
end
sourceLength += real.Size.Y
rigLength += rigPart.Size.Y
end
if sourceLength < 0.01 then
return nil
end
return rigLength / sourceLength
end
local function getWholeLegScale(character, side)
-- Same strategy as the V7 arms: use the combined leg length rather
-- than enlarging each short leg segment by its own height ratio.
local sourceLength, rigLength = 0, 0
for _, suffix in ipairs({"UpperLeg", "LowerLeg", "Foot"}) do
local name = side .. suffix
local real = character:FindFirstChild(name)
local rigPart = R15OriginalAppearance[name]
if not real or not real:IsA("MeshPart") or not rigPart then
return nil
end
sourceLength += real.Size.Y
rigLength += rigPart.Size.Y
end
if sourceLength < 0.01 then
return nil
end
return rigLength / sourceLength
end
local function copyR15VisualChildren(sourcePart, fakePart)
-- Mesh geometry and body attachments must use matching axis scaling.
-- Earlier versions scaled ALL attachments by the height multiplier;
-- on short-limbed packages that pushed arm/shoulder attachments outward.
local sourceSize = sourcePart.Size
local newSize = fakePart.Size
local scaleX = sourceSize.X > 0.001 and newSize.X / sourceSize.X or 1
local scaleY = sourceSize.Y > 0.001 and newSize.Y / sourceSize.Y or 1
local scaleZ = sourceSize.Z > 0.001 and newSize.Z / sourceSize.Z or 1
for _, child in ipairs(sourcePart:GetChildren()) do
local copyIt = child:IsA("SurfaceAppearance")
or child:IsA("Decal")
or child:IsA("Texture")
if R15_COPY_CAGE_COMPONENTS then
copyIt = copyIt
or child:IsA("WrapTarget")
or child:IsA("Attachment")
or child:IsA("Bone")
end
if copyIt then
local ok, copy = pcall(function()
return child:Clone()
end)
if ok and copy then
if copy:IsA("Attachment") then
-- Scale attachment position by the ACTUAL dimensions
-- of the copied MeshPart on each axis (not height only).
local sourceFrame = child.CFrame
local p = sourceFrame.Position
copy.CFrame = CFrame.new(Vector3.new(
p.X * scaleX, p.Y * scaleY, p.Z * scaleZ
)) * sourceFrame.Rotation
end
copy:SetAttribute(COPIED_BODY_APPEARANCE_ATTR, true)
copy.Parent = fakePart
end
end
end
end
local function restoreR15TemplatePart(fakePart, original)
if not original or not fakePart:IsA("MeshPart") then
return
end
clearCopiedR15Visuals(fakePart)
local ok, err = pcall(function()
fakePart:ApplyMesh(original.Mesh)
end)
if not ok then
warn("[Bike Anims] Failed to restore template " .. fakePart.Name .. ": " .. tostring(err))
end
fakePart.Size = original.Size
fakePart.Material = original.Material
fakePart.MaterialVariant = original.MaterialVariant
fakePart.Reflectance = original.Reflectance
end
local function resetR15Appearance()
table.clear(R15BodyUniformScales)
for _, name in ipairs(R15_BODY_PART_NAMES) do
local fakePart = bike.Misc.Anims.R15:FindFirstChild(name)
local original = R15OriginalAppearance[name]
if fakePart and fakePart:IsA("MeshPart") then
restoreR15TemplatePart(fakePart, original)
end
end
end
local function applyR15Appearance(C)
local armScales = {}
if R15_SMART_ARM_FIT then
armScales.Left = getWholeArmScale(C, "Left")
armScales.Right = getWholeArmScale(C, "Right")
end
local legScales = {}
if R15_SMART_LEG_FIT then
legScales.Left = getWholeLegScale(C, "Left")
legScales.Right = getWholeLegScale(C, "Right")
end
for _, name in ipairs(R15_BODY_PART_NAMES) do
local realPart = C:FindFirstChild(name)
local fakePart = bike.Misc.Anims.R15:FindFirstChild(name)
local original = R15OriginalAppearance[name]
if fakePart and fakePart:IsA("MeshPart") then
-- Keep all the original motorcycle rig parts and welds in place.
-- Only update their appearance while someone is riding.
restoreR15TemplatePart(fakePart, original)
if realPart and realPart:IsA("MeshPart") then
local ok, err = pcall(function()
fakePart:ApplyMesh(realPart)
end)
if not ok then
warn("[Bike Anims] Mesh copy failed for " .. name .. ": " .. tostring(err))
end
local uniformScale = 1
if original then
-- Arms, legs, and torso are held in position by independent
-- controllers welded to the bike. Changing their length
-- without moving those controllers leaves body gaps.
-- Match the original animated part's vertical length,
-- and scale the other dimensions proportionally.
if R15_UNIFORM_RIG_FIT and realPart.Size.Y > 0.001 then
uniformScale = original.Size.Y / realPart.Size.Y
local widthScale = uniformScale
local thicknessLimit = math.huge
if R15_SMART_ARM_FIT then
local side = name:match("^(Left)") or name:match("^(Right)")
local isArm = name:find("Arm", 1, true)
or name:find("Hand", 1, true)
if isArm and side and armScales[side] then
-- A 0.25-stud upper arm should not become 4x
-- thicker merely because the bike's upper
-- arm joint measures 1 stud in height.
widthScale = math.min(
uniformScale,
armScales[side] * R15_ARM_LENGTH_SCALE_ALLOWANCE
)
thicknessLimit = R15_ARM_MAX_RIG_THICKNESS
end
end
if R15_SMART_LEG_FIT then
local side = name:match("^(Left)") or name:match("^(Right)")
local isLeg = name:find("Leg", 1, true)
or name:find("Foot", 1, true)
if isLeg and side and legScales[side] then
widthScale = math.min(
uniformScale,
legScales[side] * R15_LEG_LENGTH_SCALE_ALLOWANCE
)
thicknessLimit = name:find("Foot", 1, true)
and R15_FOOT_MAX_RIG_THICKNESS
or R15_LEG_MAX_RIG_THICKNESS
end
end
local fitted = realPart.Size * widthScale
local shape = math.clamp(R15_SHAPE_PRESERVATION, 0, 1)
fakePart.Size = Vector3.new(
math.max(0.05, math.min(
original.Size.X * thicknessLimit,
original.Size.X + (fitted.X - original.Size.X) * shape
)),
original.Size.Y,
math.max(0.05, math.min(
original.Size.Z * thicknessLimit,
original.Size.Z + (fitted.Z - original.Size.Z) * shape
))
)
-- V21: natural-length R15 hands. V20's rig hand template
-- is 0.80 X 0.315 Y X 0.90 Z studs, and its Y clamp
-- restricted every palm to 0.195-0.347 studs long while
-- allowing up to ~1 stud in width/depth. That generated
-- the flat oversized mittens seen on custom packages.
--
-- Use the wearer's hand-to-forearm ratios, transferred
-- into the fixed animated forearm, with human-readable
-- silhouette bounds. Critically, never cap palm LENGTH
-- to the original mannequin's 0.315-stud placeholder.
-- The existing hand grip controller, wrist attachments,
-- left V20 wrist solve, right wrist solve, and all
-- animation welds are unchanged.
if name == "LeftHand" or name == "RightHand" then
local side = name:match("^(Left)") or "Right"
local sourceForearm = C:FindFirstChild(side .. "LowerArm")
local fittedForearm = bike.Misc.Anims.R15:FindFirstChild(side .. "LowerArm")
if sourceForearm and sourceForearm:IsA("MeshPart")
and fittedForearm and fittedForearm:IsA("MeshPart")
then
local sourceSize = sourceForearm.Size
local fittedSize = fittedForearm.Size
local handSize = realPart.Size
local function relativeSize(handAxis, armAxis, rigAxis)
return rigAxis * (handAxis / math.max(armAxis, 0.05))
end
-- Y is wrist-to-fingers in an R15 hand.
-- Preserve the relative length of the original
-- avatar hand while ensuring an actual palm,
-- rather than a flattened 0.3-stud plate.
local minimumLength = math.max(0.45, fittedSize.Y * 0.34)
local maximumLength = math.max(minimumLength, fittedSize.Y * 0.55)
local length = math.clamp(
relativeSize(handSize.Y, sourceSize.Y, fittedSize.Y),
minimumLength, maximumLength
)
-- Width and depth remain avatar-relative, but
-- cannot exceed the wrist/forearm silhouette or
-- grow wider/deeper than a natural palm.
-- For the stock 1.305-stud forearm the result
-- is approximately 0.45-0.72 studs in length.
local maxWidth = math.max(0.27,
math.min(fittedSize.X * 0.72, length * 0.82))
local maxDepth = math.max(0.21,
math.min(fittedSize.Z * 0.58, length * 0.70))
local width = math.clamp(
relativeSize(handSize.X, sourceSize.X, fittedSize.X),
0.27, maxWidth
)
local depth = math.clamp(
relativeSize(handSize.Z, sourceSize.Z, fittedSize.Z),
0.21, maxDepth
)
fakePart.Size = Vector3.new(width, length, depth)
end
end
else
fakePart.Size = original.Size
end
end
R15BodyUniformScales[name] = uniformScale
fakePart.Color = realPart.Color
fakePart.Material = realPart.Material
fakePart.MaterialVariant = realPart.MaterialVariant
fakePart.Reflectance = realPart.Reflectance
copyR15VisualChildren(realPart, fakePart)
elseif realPart and realPart:IsA("BasePart") then
fakePart.Color = realPart.Color
end
end
end
end
local function setRealR15BodyHidden(C)
for _, name in ipairs(R15_BODY_PART_NAMES) do
local part = C:FindFirstChild(name)
if part and part:IsA("BasePart") then
if part:GetAttribute(R15_REAL_TRANSPARENCY_ATTR) == nil then
part:SetAttribute(R15_REAL_TRANSPARENCY_ATTR, part.Transparency)
end
part.Transparency = 1
end
end
end
local function restoreRealR15Body(C)
for _, name in ipairs(R15_BODY_PART_NAMES) do
local part = C:FindFirstChild(name)
if part and part:IsA("BasePart") then
local oldTransparency = part:GetAttribute(R15_REAL_TRANSPARENCY_ATTR)
if oldTransparency ~= nil then
part.Transparency = oldTransparency
part:SetAttribute(R15_REAL_TRANSPARENCY_ATTR, nil)
end
end
end
end
local function copyR15BodyAccessories(C)
if not R15_COPY_BODY_ACCESSORIES then
return
end
local rig = bike.Misc.Anims.R15
local rigHumanoid = rig:FindFirstChildOfClass("Humanoid")
local realHead = C:FindFirstChild("Head")
if not rigHumanoid or not realHead then
return
end
-- Head accessories remain on the ACTUAL head, which the working
-- motorcycle script already welds onto its original animated NewHead.
-- Everything attached to the body is cloned into the animated body.
for _, accessory in ipairs(C:GetChildren()) do
if accessory:IsA("Accessory") and not isHeadAccessory(accessory, realHead) then
local ok, copy = pcall(function() return accessory:Clone() end)
if ok and copy then
copy:SetAttribute(COPIED_ACCESSORY_ATTR, true)
local handle = copy:FindFirstChild("Handle")
if handle and handle:IsA("BasePart") then
local oldAccessoryWeld = handle:FindFirstChild("AccessoryWeld")
if oldAccessoryWeld then
oldAccessoryWeld:Destroy()
end
end
for _, d in ipairs(copy:GetDescendants()) do
if d:IsA("BasePart") then
d.Anchored = false
d.CanCollide = false
d.CanTouch = false
d.CanQuery = false
d.Massless = true
end
end
local added, err = pcall(function()
-- Called from the SERVER. This finds the matching
-- attachments that copyR15VisualChildren just installed.
rigHumanoid:AddAccessory(copy)
end)
if not added then
warn("[Bike Anims] Could not attach " .. accessory.Name .. ": " .. tostring(err))
copy:Destroy()
elseif handle and handle:IsA("BasePart")
and not handle:FindFirstChild("AccessoryWeld") then
-- Some unconventional R15 rigs do not get an automatic
-- weld from AddAccessory. Attach to the original bike
-- rig body part manually if an exact attachment matches.
local welded = false
for _, handleAttachment in ipairs(handle:GetChildren()) do
if handleAttachment:IsA("Attachment") then
for _, bodyPart in ipairs(rig:GetChildren()) do
if bodyPart:IsA("BasePart") then
local bodyAttachment = bodyPart:FindFirstChild(handleAttachment.Name)
if bodyAttachment and bodyAttachment:IsA("Attachment") then
local weld = Instance.new("Weld")
weld.Name = "AccessoryWeld"
weld.Part0 = bodyPart
weld.Part1 = handle
weld.C0 = bodyAttachment.CFrame
weld.C1 = handleAttachment.CFrame
weld.Parent = handle
welded = true
break
end
end
end
end
if welded then break end
end
if not welded then
warn("[Bike Anims] No matching animated attachment for " .. accessory.Name)
copy:Destroy() -- never leave an unwelded accessory floating
end
end
else
warn("[Bike Anims] Could not clone body accessory " .. accessory.Name)
end
end
end
end
--============================================================
-- SHOW FAKE R6 BODY
--============================================================
local function showR6FakeBody()
for _, model in ipairs(
bike.Misc.Anims.R6:GetChildren()
) do
if model:FindFirstChild("Parts")
and not model.Parts:
FindFirstChildOfClass(
"Humanoid"
)
then
local hum =
Instance.new("Humanoid")
hum.RigType =
Enum.HumanoidRigType.R6
hum.RequiresNeck =
false
hum.BreakJointsOnDeath =
false
hum.AutoJumpEnabled =
false
hum.AutoRotate =
false
hum.Sit =
true
hum.Parent =
model.Parts
end
end
bike.Misc.Anims.R6.Torso.Parts.Torso.Transparency =
0
bike.Misc.Anims.R6.RightArm.Parts["Right Arm"].Transparency =
0
bike.Misc.Anims.R6.LeftArm.Parts["Left Arm"].Transparency =
0
bike.Misc.Anims.R6.RightLeg.Parts["Right Leg"].Transparency =
0
bike.Misc.Anims.R6.LeftLeg.Parts["Left Leg"].Transparency =
0
bike.Misc.Anims.R6.Head.Parts.NewHead.Transparency =
1
end
--============================================================
-- SHOW FAKE R15 BODY
--============================================================
local function showR15FakeBody()
if not bike.Misc.Anims.R15:
FindFirstChildOfClass(
"Humanoid"
)
then
local hum =
Instance.new("Humanoid")
hum.RigType =
Enum.HumanoidRigType.R15
hum.AutoJumpEnabled =
false
hum.AutoRotate =
false
hum.Sit =
true
hum.Parent =
bike.Misc.Anims.R15
end
local names = {
"RightUpperArm",
"RightLowerArm",
"RightHand",
"RightUpperLeg",
"RightLowerLeg",
"RightFoot",
"LeftUpperArm",
"LeftLowerArm",
"LeftHand",
"LeftUpperLeg",
"LeftLowerLeg",
"LeftFoot",
"LowerTorso",
"UpperTorso"
}
for _, name in ipairs(names) do
local part =
bike.Misc.Anims.R15:
FindFirstChild(name)
if part then
part.Transparency =
0
end
end
bike.Misc.Anims.R15.NewHead.Transparency =
1
end
--============================================================
-- HIDE FAKE BODY
--============================================================
local function hideR6FakeBody()
bike.Misc.Anims.R6.Head.Parts.NewHead.Transparency =
1
bike.Misc.Anims.R6.Torso.Parts.Torso.Transparency =
1
bike.Misc.Anims.R6.RightArm.Parts["Right Arm"].Transparency =
1
bike.Misc.Anims.R6.LeftArm.Parts["Left Arm"].Transparency =
1
bike.Misc.Anims.R6.RightLeg.Parts["Right Leg"].Transparency =
1
bike.Misc.Anims.R6.LeftLeg.Parts["Left Leg"].Transparency =
1
end
local function hideR15FakeBody()
local names = {
"NewHead",
"RightUpperArm",
"RightLowerArm",
"RightHand",
"RightUpperLeg",
"RightLowerLeg",
"RightFoot",
"LeftUpperArm",
"LeftLowerArm",
"LeftHand",
"LeftUpperLeg",
"LeftLowerLeg",
"LeftFoot",
"LowerTorso",
"UpperTorso"
}
for _, name in ipairs(names) do
local part =
bike.Misc.Anims.R15:
FindFirstChild(name)
if part then
part.Transparency =
1
end
end
end
--============================================================
-- CLOTHING
--============================================================
local function copyR6Clothes(C)
for _, object in ipairs(
C:GetChildren()
) do
if object:IsA("Shirt") then
object:Clone().Parent =
bike.Misc.Anims.R6.Torso.Parts
object:Clone().Parent =
bike.Misc.Anims.R6.RightArm.Parts
object:Clone().Parent =
bike.Misc.Anims.R6.LeftArm.Parts
elseif object:IsA("ShirtGraphic") then
object:Clone().Parent =
bike.Misc.Anims.R6.Torso.Parts
elseif object:IsA("Pants") then
object:Clone().Parent =
bike.Misc.Anims.R6.Torso.Parts
object:Clone().Parent =
bike.Misc.Anims.R6.RightLeg.Parts
object:Clone().Parent =
bike.Misc.Anims.R6.LeftLeg.Parts
end
end
end
local function copyR15Clothes(C)
for _, object in ipairs(
C:GetChildren()
) do
if object:IsA("Shirt")
or object:IsA("Pants")
or object:IsA("ShirtGraphic")
or object:IsA("BodyColors")
then
object:Clone().Parent =
bike.Misc.Anims.R15
end
end
end
--============================================================
-- CLOTHING CLEANUP
--============================================================
local function cleanupR6Clothes()
local containers = {
bike.Misc.Anims.R6.Torso.Parts,
bike.Misc.Anims.R6.RightArm.Parts,
bike.Misc.Anims.R6.LeftArm.Parts,
bike.Misc.Anims.R6.RightLeg.Parts,
bike.Misc.Anims.R6.LeftLeg.Parts
}
for _, container in ipairs(containers) do
for _, object in ipairs(
container:GetChildren()
) do
if not object:IsA("BasePart") then
object:Destroy()
end
end
end
end
local function cleanupR15Clothes()
for _, object in ipairs(
bike.Misc.Anims.R15:
GetChildren()
) do
if not object:IsA("BasePart")
and not object:IsA("Model")
then
object:Destroy()
end
end
end
--============================================================
-- V19: torso-to-tank clearance (visual mannequin only)
--
-- The lower torso is anchored to DriveSeat through LowerTorso.X.M.
-- The old 0.08-up/0.12-back fixed mount often puts thick R15 torso
-- meshes into the tank. Offset this MOTOR's seat-space C1, never
-- the real player's joints or bike chassis. Arms remain on the grips.
-- Small corrections preserve the original animation and leg alignment.
--============================================================
local R15_TORSO_EXTRA_UP = 0.075 -- studs beyond existing AnimSetup offset
local R15_TORSO_EXTRA_BACK = 0.10 -- +Z in DriveSeat space, away from bars
local R15_TORSO_BULK_UP = 0.10 -- extra up per stud beyond template depth
local R15_TORSO_BULK_BACK = 0.18 -- extra back per stud beyond template depth
local torsoRoot = bike.Misc.Anims.R15.Torso.LowerTorso.X
local torsoSeatJoint = torsoRoot:FindFirstChild("M")
local defaultTorsoSeatC1 = torsoSeatJoint and torsoSeatJoint.C1
local function resetTorsoClearance()
if torsoSeatJoint and defaultTorsoSeatC1 then
torsoSeatJoint.C1 = defaultTorsoSeatC1
end
end
local function fitTorsoClearance()
if not (torsoSeatJoint and defaultTorsoSeatC1) then return end
local template = R15OriginalAppearance.UpperTorso
local fitted = bike.Misc.Anims.R15:FindFirstChild("UpperTorso")
local excessDepth = (template and fitted)
and math.max(0, fitted.Size.Z - template.Size.Z) or 0
local extraUp = R15_TORSO_EXTRA_UP
+ math.min(0.07, excessDepth * R15_TORSO_BULK_UP)
local extraBack = R15_TORSO_EXTRA_BACK
+ math.min(0.10, excessDepth * R15_TORSO_BULK_BACK)
torsoSeatJoint.C1 = CFrame.new(0, extraUp, extraBack) * defaultTorsoSeatC1
end
--============================================================
-- CREATE PLAYER
--============================================================
local resetArmWelds
F.CreatePlayer = function(C)
resetArmWelds()
resetTorsoClearance()
local humanoid =
C and C:
FindFirstChildOfClass(
"Humanoid"
)
if not humanoid then
return
end
local rigType =
getAnimationRigType(C)
--========================================================
-- R6
--========================================================
if rigType ==
Enum.HumanoidRigType.R6
then
C.Torso.Transparency =
1
C.Head.Transparency =
0
C["Right Arm"].Transparency =
1
C["Left Arm"].Transparency =
1
C["Right Leg"].Transparency =
1
C["Left Leg"].Transparency =
1
showR6FakeBody()
applyR6SkinTone(C)
copyR6CharacterMeshes(C)
copyR6Clothes(C)
hideNonHeadAccessories(C)
attachRealHead(
C,
rigType
)
--========================================================
-- R15
--========================================================
else
setRealR15BodyHidden(C)
C.Head.Transparency = 0
-- Keep the entire known-working motorcycle pose controller.
showR15FakeBody()
applyR15Appearance(C)
fitTorsoClearance()
copyR15Clothes(C)
copyR15BodyAccessories(C)
hideNonHeadAccessories(C)
attachRealHead(C, rigType)
end
end
--============================================================
-- REMOVE PLAYER
--============================================================
F.RemovePlayer = function(
C,
child
)
resetArmWelds()
resetTorsoClearance()
if not C
or not child
or child.Name ~= "SeatWeld"
then
return
end
local humanoid =
C:FindFirstChildOfClass(
"Humanoid"
)
if not humanoid then
return
end
local rigType =
getAnimationRigType(C)
--------------------------------------------------------
-- HEAD FIRST
--------------------------------------------------------
restoreRealHead(C)
restoreAccessories(C)
--========================================================
-- R6
--========================================================
if rigType ==
Enum.HumanoidRigType.R6
then
C.Torso.Transparency =
0
C.Head.Transparency =
0
C["Right Arm"].Transparency =
0
C["Left Arm"].Transparency =
0
C["Right Leg"].Transparency =
0
C["Left Leg"].Transparency =
0
hideR6FakeBody()
cleanupR6Clothes()
--========================================================
-- R15
--========================================================
else
restoreRealR15Body(C)
C.Head.Transparency = 0
hideR15FakeBody()
-- Removes copied shirts/pants/accessories and the temporary fake
-- Humanoid, while preserving all the bike's own animation parts.
cleanupR15Clothes()
resetR15Appearance()
end
end
--============================================================
-- SERVER-SIDE DISMOUNT CLEANUP
--============================================================
-- Arm visuals are calculated only by the occupying rider's client.
-- Server mirrors validated weld positions for other players. There is no
-- competing independent Heartbeat solver.
local armWelds = {}
local originalArmC0 = {}
local rig = bike.Misc.Anims.R15
for _, side in ipairs({"Left", "Right"}) do
local arm = rig:FindFirstChild(side .. "Arm")
armWelds[side] = {}
if arm then
for _, pair in ipairs({{"UpperArm", "UpperArm"}, {"LowerArm", "LowerArm"}}) do
local control = arm:FindFirstChild(pair[1])
local pivot = control and control:FindFirstChild("X")
local mesh = rig:FindFirstChild(side .. pair[2])
if pivot and mesh then
for _, joint in ipairs(pivot:GetChildren()) do
if joint:IsA("Weld") and joint.Part0 == pivot and joint.Part1 == mesh then
armWelds[side][pair[1]] = joint
originalArmC0[joint] = joint.C0
break
end
end
end
end
end
end
resetArmWelds = function()
for weld, offset in pairs(originalArmC0) do
if weld.Parent then weld.C0 = offset end
end
end
local lastArmSync = {}
F.SyncArmWelds = function(player, lu, ll, ru, rl)
local occupant = bike.DriveSeat.Occupant
if not occupant or not occupant.Parent or game.Players:GetPlayerFromCharacter(occupant.Parent) ~= player then
return
end
local now = os.clock()
if now - (lastArmSync[player] or 0) < 0.07 then return end
local offsets = {lu, ll, ru, rl}
local joints = {
armWelds.Left.UpperArm, armWelds.Left.LowerArm,
armWelds.Right.UpperArm, armWelds.Right.LowerArm
}
for i = 1, 4 do
local cf, joint = offsets[i], joints[i]
if typeof(cf) ~= "CFrame" or not joint then return end
local p = cf.Position
if p.X ~= p.X or p.Y ~= p.Y or p.Z ~= p.Z or p.Magnitude > 15 then return end
end
lastArmSync[player] = now
for i = 1, 4 do
joints[i].C0 = offsets[i]
end
end
local activeCharacter = nil
if bike.DriveSeat.Occupant then
activeCharacter = bike.DriveSeat.Occupant.Parent
end
bike.DriveSeat.ChildAdded:Connect(function(child)
if child:IsA("Weld")
and child.Name == "SeatWeld"
then
local riderPart =
child.Part1
if riderPart then
activeCharacter =
riderPart.Parent
end
end
end)
bike.DriveSeat.ChildRemoved:Connect(function(child)
if not child:IsA("Weld")
or child.Name ~= "SeatWeld"
then
return
end
local character =
activeCharacter
activeCharacter = nil
if not character
and child.Part1
then
character =
child.Part1.Parent
end
if character then
F.RemovePlayer(
character,
child
)
end
end)
--remote
script.Parent.OnServerEvent:Connect(
function(
player,
functionName,
...
)
if functionName == "SyncArmWelds" then
F.SyncArmWelds(player, ...)
return
end
local callback =
F[functionName]
if callback then
callback(...)
else
warn(
"[Bike Anims] Unknown function:",
functionName
)
end
end
)
--lceyDex on Discord if you need assistanceRealistic Dismount Physics
Developed a safer and more realistic dismount system that prevents players from being launched or experiencing physics glitches when exiting the motorcycle. Improved the transition between riding and walking to create a smoother dismount experience.

Universal R15 & R6 Package Support
Adjusted the motorcycle's arm & leg animation system to support both R6 and R15 avatars, including different Roblox character packages and body proportions. Ensured consistent leg positioning and animations across different avatar types.