Skip to content
All projects
Roblox & Games

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.

Picture displaying the preset R6 & R15 animation packages

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.

A-Chassis 1.7.2M Github Repo Head Accessory Issue
After fixing for the commission, I posted my fix publicly

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.

luaFEAnims
--[[	
		             _____ _                   _     
	     /\         / ____| |                 (_)    
	    /  \ ______| |    | |__   __ _ ___ ___ _ ___ 
	   / /\ \______| |    | '_ \ / _` / __/ __| / __|
	  / ____ \     | |____| | | | (_| \__ \__ \ \__ \
	 /_/    \_\     \_____|_| |_|\__,_|___/___/_|___/
	 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 assistance

Realistic 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.