How do i make a frame go move to the position depending on its rotation?

the title explains itself.

what i want:

the code:

k.Hitbox.Activated:Connect(function() if selectedButton then return end tweenService:Create(k.UIScale, TweenInfo.new(0.3, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0, false, 0), {Scale = 1.1}):Play() end)		
	k.Hitbox.MouseEnter:Connect(function() 
		if selectedButton then return end
		k:WaitForChild('ButtonEnter'):Play() 
		k.ZIndex = 2
		
		
		module.setShadowTransparency('All', 0.6)
		module.setShadowTransparency(k, 1)
	end)
	k.Hitbox.MouseLeave:Connect(function()
		if selectedButton then return end
		k:WaitForChild('ButtonLeave'):Play() 
		k.ZIndex = 1
		
		module.setShadowTransparency('All', 1)
	end)

you just need a simple math

local function moveFrameBasedOnRotation(frame, angle, distance)
    local radians = math.rad(angle)
    local deltaX = math.cos(radians) * distance
    local deltaY = math.sin(radians) * distance
    frame.Position = UDim2.new(
        frame.Position.X.Scale, 
        frame.Position.X.Offset + deltaX,
        frame.Position.Y.Scale, 
        frame.Position.Y.Offset + deltaY
    )
end

k.Hitbox.Activated:Connect(function()
    if selectedButton then return end
    tweenService:Create(k.UIScale, TweenInfo.new(0.3, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0, false, 0), {Scale = 1.1}):Play()
    moveFrameBasedOnRotation(k, k.Rotation, 20)
end)

k.Hitbox.MouseEnter:Connect(function() 
    if selectedButton then return end
    k:WaitForChild('ButtonEnter'):Play() 
    k.ZIndex = 2
    module.setShadowTransparency('All', 0.6)
    module.setShadowTransparency(k, 1)
    moveFrameBasedOnRotation(k, k.Rotation, 10)
end)

k.Hitbox.MouseLeave:Connect(function()
    if selectedButton then return end
    k:WaitForChild('ButtonLeave'):Play() 
    k.ZIndex = 1
    module.setShadowTransparency('All', 1)
    moveFrameBasedOnRotation(k, k.Rotation, -10)
end)

well, i tried it but it didnt turn out very well.
https://gyazo.com/f539895bc8c1e8a67fb9b3ee727f73e4

Also, do you know how to fix this problem that i showed on the video? like, its pretty buggy when you hover the mouse between 2 cards.

yeah a debounce should work well
can you try this

local tweenService = game:GetService("TweenService")
local userInputService = game:GetService("UserInputService")

local debounceTime = 0.1
local lastMouseMoveTime = 0

local function moveFrameBasedOnRotation(frame, angle, distance)
    local radians = math.rad(angle)
    local deltaX = math.cos(radians) * distance
    local deltaY = math.sin(radians) * distance
    frame.Position = UDim2.new(
        frame.Position.X.Scale, 
        frame.Position.X.Offset + deltaX,
        frame.Position.Y.Scale, 
        frame.Position.Y.Offset + deltaY
    )
end

local function handleMouseEnter(k)
    if selectedButton then return end
    k:WaitForChild('ButtonEnter'):Play() 
    k.ZIndex = 2
    module.setShadowTransparency('All', 0.6)
    module.setShadowTransparency(k, 1)
    moveFrameBasedOnRotation(k, k.Rotation, 10)
end

local function handleMouseLeave(k)
    if selectedButton then return end
    k:WaitForChild('ButtonLeave'):Play() 
    k.ZIndex = 1
    module.setShadowTransparency('All', 1)
    moveFrameBasedOnRotation(k, k.Rotation, -10)
end

k.Hitbox.Activated:Connect(function()
    if selectedButton then return end
    tweenService:Create(k.UIScale, TweenInfo.new(0.3, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0, false, 0), {Scale = 1.1}):Play()
    moveFrameBasedOnRotation(k, k.Rotation, 20)
end)

k.Hitbox.MouseEnter:Connect(function() 
    if os.clock() - lastMouseMoveTime < debounceTime then return end
    lastMouseMoveTime = os.clock()
    handleMouseEnter(k)
end)

k.Hitbox.MouseLeave:Connect(function()
    if os.clock() - lastMouseMoveTime < debounceTime then return end
    lastMouseMoveTime = os.clock()
    handleMouseLeave(k)
end)

userInputService.InputChanged:Connect(function(input)
    if input.UserInputType == Enum.UserInputType.MouseMovement then
        local mousePosition = userInputService:GetMouseLocation()
        local framePosition = k.AbsolutePosition
        local frameSize = k.AbsoluteSize
        if mousePosition.X >= framePosition.X and mousePosition.X <= framePosition.X + frameSize.X
        and mousePosition.Y >= framePosition.Y and mousePosition.Y <= framePosition.Y + frameSize.Y then
            handleMouseEnter(k)
        else
            handleMouseLeave(k)
        end
    end
end)

i tried it, but its now like this:

https://gyazo.com/a101d09e5f163f4cbafa81f772c5d08c

and also the frame aren’t going to where they’re rotated to… instead they’re going to the side.

can you provide me your full code

it’s pretty long, also my coding skills are not the best, i hope you don’t mind.

--// Services
local runService = game:GetService('RunService')
local userInputService = game:GetService('UserInputService')
local replicatedStorage = game:GetService('ReplicatedStorage')
local tweenService = game:GetService('TweenService')
local players = game:GetService('Players')

--// Folders
local arenasFolder = workspace:WaitForChild('Arena')
local MapName = arenasFolder:WaitForChild("MapName").Value
local modules = replicatedStorage:WaitForChild('Modules')
local units = modules:WaitForChild('Units')
local events = replicatedStorage:WaitForChild('Events')
local assets = replicatedStorage:WaitForChild('Assets')
local sounds = script:WaitForChild('Sounds')

--// Player
local player = players.LocalPlayer
local mouse = player:GetMouse()
local camera = workspace.CurrentCamera
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild('Humanoid')
local animator = humanoid:WaitForChild('Animator')
local turn = arenasFolder:WaitForChild('Turn')
local collection = player:WaitForChild('Collection')
local deck = player:WaitForChild('Deck')

--// HUD
local playerui = player.PlayerGui
local matchEndHud = playerui:WaitForChild('MatchEnd')
local gameHud = playerui:WaitForChild('GameHUD')
local cardsFrame = gameHud:WaitForChild('cardsFrame')
local unitInfo = gameHud:WaitForChild('UnitInfo')
local unitSettingsUI = gameHud:WaitForChild('UnitSettings')
local speechlabel = gameHud:WaitForChild('SpeechText')
local matchEndLine = matchEndHud:WaitForChild('Line')
local highlight = script:WaitForChild('Hover')
local buyCards = gameHud:WaitForChild('BuyCards')
--local arrow = script:WaitForChild('Arrow')
local playerUnits = gameHud:WaitForChild('PlayerUnits')
local buttons = gameHud:WaitForChild('Buttons')

--// Modules
local unit_data_holder = require(modules:WaitForChild('UnitDataHolder'))
local ConfettiCannon = require(script:WaitForChild('ConfettiParticles'))
local playlist = require(script:WaitForChild('Playlist'))
local gradientList = require(script:WaitForChild('Gradients'))

--//UserInputService

local IsMobile = userInputService.TouchEnabled
local IsConsole = userInputService.GamepadEnabled

--// Configurations
local AmountOfConfetti = 25
local spinAngle = 0
local debounceTime = 0.1
local lastMouseMoveTime = 0

local model = nil
local placing = nil
local tile = nil
local selectedButton = nil
local debounce = false

local onSettings = false
local confettiActive = false

ConfettiCannon.setGravity(Vector2.new(0,1))

--// Tables
local losingTexts = {
	'The cake was a lie, why\'d you eat it?';
	'Mission failed, we\'ll get em\' next time!';
	'Wasted!';
	'Bro lost 💀';
	'Womp womp!';
	'Please go back to the tutorial, i beg you.';
	'You failed! boohoo!!!!';
	'[Insert sad trumpet]';
	'Mortis';
	'🤡';
	'You should revise your strategy. NOW!';
	'See you later, Alligator!';	
	'Thy end was now🙏';
	'Bro didn\'t prepare thyself'
};

local confetti = {}
local confettiColors = {Color3.fromRGB(255,255,100), Color3.fromRGB(255,100,100), Color3.fromRGB(164, 74, 255), Color3.fromRGB(41, 255, 8), Color3.fromRGB(255, 0, 144)}
local module = {}

--[[ LOCAL FUNCTIONS ]]

local function getTimer() return events.getInformation:InvokeServer('Timer') end
local function getTurn() return events.getInformation:InvokeServer('Turn') end
local function getStuds() return player:WaitForChild('Studs').Value end
local function getHP() return character:WaitForChild('HP').Value end
local function getRound() return events.getInformation:InvokeServer('Round') end

local function moveFrameBasedOnRotation(frame, angle, distance)
	local radians = math.rad(angle)
	local deltaX = math.cos(radians) * distance
	local deltaY = math.sin(radians) * distance
	frame.Position = UDim2.new(
		frame.Position.X.Scale, 
		frame.Position.X.Offset + deltaX,
		frame.Position.Y.Scale, 
		frame.Position.Y.Offset + deltaY
	)
end

local function handleMouseEnter(k)
	if selectedButton then return end
	k:WaitForChild('ButtonEnter'):Play() 
	k.ZIndex = 2
	module.setShadowTransparency('All', 0.6)
	module.setShadowTransparency(k, 1)
	moveFrameBasedOnRotation(k, k.Rotation, 10)
end

local function handleMouseLeave(k)
	if selectedButton then return end
	k:WaitForChild('ButtonLeave'):Play() 
	k.ZIndex = 1
	module.setShadowTransparency('All', 1)
	moveFrameBasedOnRotation(k, k.Rotation, -10)
end

local function layoutChildren()
	local segmentCount = #cardsFrame.Path2D:GetControlPoints()
	local objectToLayout = {}

	for _, child in pairs(cardsFrame:GetChildren()) do
		if child:IsA("GuiObject") and not child:IsA("Path2D") then
			table.insert(objectToLayout, child)
		end
	end

	for idx, child in pairs(objectToLayout) do
		local t = idx / (#objectToLayout + 1)
		local tangent = cardsFrame.Path2D:GetTangentOnCurveArcLength(t)
		child.Position = cardsFrame.Path2D:GetPositionOnCurveArcLength(t)
		child.Rotation = math.deg(math.atan2(tangent.Y, tangent.X))
	end
end


local function getUnitAmount(unitName:string)
	local amountFound = 0
	
	for __, value in pairs(player.cardsFolder:GetChildren()) do
		if value.Name ~= unitName then continue end
		amountFound += 1
	end

	for __, tiles : BasePart in pairs(arenasFolder.Map[arenasFolder.MapName.Value].Tiles[player.Name]:GetChildren()) do
		if not tiles:FindFirstChild(unitName) then continue end
		amountFound += 1
	end
	
	return amountFound
end

local function setTransparencyEnemy(number:number)
	for _, tiles in pairs(arenasFolder:WaitForChild('Map'):GetDescendants()) do
		if not tiles:IsA('Folder') then continue end
		if tiles.Parent.Name ~= 'Tiles' then continue end
		if tiles.Name == player.Name or tiles.Name == 'MiddleTerrain' then continue end
		local enemyTiles = tiles
		
		if number == 0 then arenasFolder[enemyTiles.Name..'_Fog'].ParticleEmitter.Enabled = false end
		if number == 1 then arenasFolder[enemyTiles.Name..'_Fog'].ParticleEmitter.Enabled = true end
		
		for __, foundTiles : BasePart in pairs(enemyTiles:GetChildren()) do			
			if not foundTiles:FindFirstChildOfClass('Model') then continue end
			local model = foundTiles:FindFirstChildOfClass('Model')
			for ignore, bp in pairs(model:GetDescendants()) do
				if bp.Name == 'HumanoidRootPart' then continue end
				if bp:IsA('BasePart') or bp:IsA('Decal') then tweenService:Create(bp, TweenInfo.new(0.2, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {Transparency = number}):Play() end
				if bp:IsA('Beam') then if number == 1 then bp.Enabled = false else bp.Enabled = true end end
			end
		end
	end
end

local function createNewLog(color:Color3, text:string)
	local log = script:WaitForChild('logTL'):Clone()
	log.Parent = matchEndHud.Logs
	log.Text = text
	log.Size = UDim2.new(1, 0, 0, 0)
	log.TextColor3 = color

	sounds:WaitForChild('NewLog'):Play()

	local tween = tweenService:Create(log, TweenInfo.new(0.4, Enum.EasingStyle.Back, Enum.EasingDirection.Out), {Size = UDim2.new(1, 0, 0.23, 0)})
	tween:Play()
	task.wait(0.4)
end

local function textWritter(object, text)
	for i = 1, #text do
		object.Text = string.sub(text, 1, i)
		sounds:WaitForChild('Writing'):Play()
		task.wait(0.02)
	end
end

local function updateUnitInfo(unit:Model)
	if not unit_data_holder[unit.Name] then return end
	unitInfo.UnitName.Text = unit.Name
	unitInfo.Icon.Image = unit_data_holder[unit.Name].icon
	unitInfo.UIGradient.Color = ColorSequence.new(gradientList[unit_data_holder[unit.Name].class])
	
	if unit:WaitForChild('HP').Value < 1 then unitInfo.Health.Amount.TextColor3 = Color3.fromRGB(255, 128, 128) else unitInfo.Health.Amount.TextColor3 = Color3.fromRGB(255, 255, 255) end
	if unit:WaitForChild('HP').Bonus.Value >= 1 then unitInfo.Health.Amount.Text = unit:WaitForChild('HP').Value unitInfo.Health.Amount.TextColor3 = Color3.fromRGB(191, 255, 138) else unitInfo.Health.Amount.Text = unit:WaitForChild('HP').Value end
	if unit:WaitForChild('DMG').Bonus.Value >= 1 then unitInfo.Damage.Amount.Text = (unit:WaitForChild('DMG').Value - unit:WaitForChild('DMG').Bonus.Value)..'<font color="rgb(191, 255, 138)">+'..unit:WaitForChild('DMG').Bonus.Value..'</font>' else unitInfo.Damage.Amount.Text = unit:WaitForChild('DMG').Value end
	
end

local function cardClicked(card:TextButton, price:number)
	if IsMobile then
		card.TouchTap:Connect(function()
			if placing ~= nil then return end
			if getTurn() ~= player.Name then module.error('Not your turn.') return end
			if getStuds() < price then module.error('You need more Studs.') return end
			
			module.setButton('Destroy', true)
			module.setButton('Cancel', true)
			module.setButton('Place', true)
			
			selectedButton = card.Parent
			tweenService:Create(cardsFrame, TweenInfo.new(0.2, Enum.EasingStyle.Back, Enum.EasingDirection.Out), {Position = UDim2.new(0.494, 0,1.1, 0)}):Play()
			module.moveCamera('Placing')
			moveFrameBasedOnRotation(card.Parent, card.Parent.Rotation, 20)

			module.setShadowTransparency('All', 0.7)
			module.setShadowTransparency(card.Parent, 1)
			placing = card.Parent.Name
		end)
	else
		card.MouseButton1Up:Connect(function()
			if placing ~= nil then return end
			if getTurn() ~= player.Name then module.error('Not your turn.') return end
			if getStuds() < price then module.error('You need more Studs.') return end
			module.setButton('Cancel', true)
			module.setButton('Destroy', true)
			
			selectedButton = card.Parent
			tweenService:Create(cardsFrame, TweenInfo.new(0.2, Enum.EasingStyle.Back, Enum.EasingDirection.Out), {Position = UDim2.new(0.494, 0,1.1, 0)}):Play()
			module.moveCamera('Placing')
			moveFrameBasedOnRotation(card.Parent, card.Parent.Rotation, 20)

			module.setShadowTransparency('All', 0.7)
			module.setShadowTransparency(card.Parent, 1)
			placing = card.Parent.Name
		end)
	end
end

local function getRandomSong()
	return playlist[math.random(1, #playlist)]
end

--local function unitSettings()
--	onSettings = true
--	unitInfo.Visible = false
--	unitSettingsUI.Visible = true
--	unitSettingsUI.Position = UDim2.new(0, mouse.X, 0, mouse.Y + 70)
--end

--[[ MODULE FUNCTIONS ]]

function module.buyCard()
	if turn.Value ~= player.Name then module.error('Not your turn.') return end
	if player:WaitForChild('Studs').Value < 2 then module.error('You don\'t have enough studs.') return end
	if #player.cardsFolder:GetChildren() >= 8 then module.error('You reached the card limit. (8)')  return end
	local result, reason = events:WaitForChild('buyCard'):InvokeServer()
	
	if not result then module.error(reason) return end
	
	sounds:WaitForChild('Cash'):Play()
	local boing = tweenService:Create(buyCards.UIScale, TweenInfo.new(0.2, Enum.EasingStyle.Back, Enum.EasingDirection.Out, 0, true), {Scale = 1.3})
	boing:Play()
 end

function module.ripCard()
	if not selectedButton then return end
	local card = selectedButton
	local sound = sounds:WaitForChild('DeleteSFX'):GetChildren()[math.random(1, #sounds:WaitForChild('DeleteSFX'):GetChildren())]
	module.setShadowTransparency(card, 0)
	sound:Play()
	card:Destroy()
	events.deleteCard:FireServer(card.Name)
	layoutChildren()
end

function module.setButton(button:string, visible:boolean)
	if not buttons:FindFirstChild(button) then return end
	buttons:FindFirstChild(button).Visible = visible
end


function module.placeUnit()
	if placing == nil or tile == nil then return end
	if debounce then return end
	debounce = true
	
	if not events.placeUnit:InvokeServer(placing, tile.CFrame) then debounce = false return end
	if getTimer() <= 5 then module.setButton('EndTurn', false) end
	
	coroutine.wrap(module.updatePossibleCards)()
	debounce = false
	module.setButton('Destroy', false)
	module.setButton('Place', false)
	placing = nil
	tile = nil

	selectedButton:Destroy()
	module.cancelPlacing(true)
	module.setShadowTransparency('All', 1)
	layoutChildren()

	sounds.Cash:Play()
	gameHud:WaitForChild('Studs').Studs.Text = getStuds()
	gameHud:WaitForChild('Studs').Studs.TextStrokeColor3 = Color3.fromRGB(255,255,255)
	gameHud:WaitForChild('Studs').Studs.Position = UDim2.new(0, 0, -0.15, 0)
	gameHud:WaitForChild('Studs').Studs:TweenPosition(UDim2.new(0,0,0,0), Enum.EasingDirection.Out, Enum.EasingStyle.Sine, 0.25, true)
	tweenService:Create(gameHud:WaitForChild('Studs').Studs, TweenInfo.new(0.25, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {TextStrokeColor3 = Color3.fromRGB(0,0,0)}):Play()
	if not camera:FindFirstChildOfClass('Model') then return end
	camera:FindFirstChildOfClass('Model'):Destroy()
	model = nil
end

function module.error(errorMSG:TextLabel)
	sounds:WaitForChild('Error'):Play()
	module.topMessage(errorMSG, Color3.fromRGB(220, 0, 0), 1.5)
end

function module.updateCard(k)
	if not k:IsA('Frame') then return end
	if not unit_data_holder[k.Name] then return end

	k.Studs.Price.Text = unit_data_holder[k.Name].price
	k.Icon.Image = unit_data_holder[k.Name].icon
	k.UnitDescription.Text = unit_data_holder[k.Name].desc
	k.Damage.Amount.Text = unit_data_holder[k.Name].dmg
	k.Health.Amount.Text = unit_data_holder[k.Name].hp
	k.UIGradient.Color = ColorSequence.new(gradientList[unit_data_holder[k.Name].class])
	cardClicked(k.Hitbox, unit_data_holder[k.Name].price)
	
	k.Hitbox.MouseEnter:Connect(function() 
		if os.clock() - lastMouseMoveTime < debounceTime then return end
		lastMouseMoveTime = os.clock()
		handleMouseEnter(k)
	end)
	k.Hitbox.MouseLeave:Connect(function()
		if os.clock() - lastMouseMoveTime < debounceTime then return end
		lastMouseMoveTime = os.clock()
		handleMouseLeave(k)
	end)
end


function module.showInfo()
	if (mouse.Target and mouse.Target:FindFirstChildOfClass('Model') and not onSettings) then
		unitInfo.Visible = true
		updateUnitInfo(mouse.Target:FindFirstChildOfClass('Model'))
		unitInfo.Position = UDim2.new(0, mouse.X, 0, mouse.Y - 70)
		return
	end
	if (mouse.Target and mouse.Target.Parent.Parent:IsA('BasePart') and not onSettings) then
		unitInfo.Visible = true
		updateUnitInfo(mouse.Target.Parent)
		unitInfo.Position = UDim2.new(0, mouse.X, 0, mouse.Y - 70)
		return
	end
		
	unitInfo.Visible = false
end

function module.addCard(object:string)
	if not unit_data_holder[object] then return end
	local newTemplate = script:WaitForChild('CardTemplate'):Clone()
	newTemplate.Parent = cardsFrame
	newTemplate.Studs.Price.Text = unit_data_holder[object].price
	newTemplate.Name = object
	newTemplate.Damage.Amount.Text = unit_data_holder[object].dmg
	newTemplate.Health.Amount.Text = unit_data_holder[object].hp
	newTemplate.Icon.Image = unit_data_holder[object].icon
	newTemplate.UnitDescription.Text = unit_data_holder[object].desc
	
	module.setShadowTransparency(newTemplate, 0.7)
	sounds:WaitForChild('CardGain'):Play()
	module.updateCard(newTemplate)
	
	layoutChildren()
end

function module.input(input:InputObject, gpe:boolean)
	if gpe then return end
	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		if (mouse.Target and mouse.Target:FindFirstChildOfClass('Model') and not onSettings) or (mouse.Target and mouse.Target.Parent.Parent:IsA('BasePart') and not onSettings) then return end
		onSettings = false
		module.placeUnit()
	elseif input.UserInputType == Enum.UserInputType.Touch then
		if (mouse.Target and mouse.Target:FindFirstChildOfClass('Model') and not onSettings) or (mouse.Target and mouse.Target.Parent.Parent:IsA('BasePart') and not onSettings) then return end
		--unitSettingsUI.Visible = false
		module.showInfo()
		onSettings = false
		--module.placeUnit()
	elseif input.KeyCode == Enum.KeyCode.Q then
		if placing == nil then return end module.cancelPlacing(false)
	elseif input.UserInputType == Enum.UserInputType.MouseMovement then
		
		if selectedButton == nil then return end
		local k = selectedButton

		local mousePosition = userInputService:GetMouseLocation()
		local framePosition = k.AbsolutePosition
		local frameSize = k.AbsoluteSize
		if mousePosition.X >= framePosition.X and mousePosition.X <= framePosition.X + frameSize.X
			and mousePosition.Y >= framePosition.Y and mousePosition.Y <= framePosition.Y + frameSize.Y then
			handleMouseEnter(k)
		else
			handleMouseLeave(k)
		end
	end
end

function module.cancelPlacing(bool:boolean)
	module.moveCamera('Normal')
	
	module.setButton('Confirm', false)
	module.setButton('Cancel', false)
	
	tweenService:Create(cardsFrame, TweenInfo.new(0.2, Enum.EasingStyle.Back, Enum.EasingDirection.Out), {Position = UDim2.new(0.494, 0,1, 0)}):Play()
	
	task.spawn(function()
		if not selectedButton then return end
		if bool then return end
		moveFrameBasedOnRotation(selectedButton, selectedButton.Rotation, -20)
		selectedButton = nil
	end)
	
	placing = nil
	tile = nil
	highlight.Parent = script
	--arrow.Parent = script
	spinAngle = 0
	if getTurn() == player.Name then if getTimer() > 5 then module.setButton('EndTurn', true) end module.setShadowTransparency('All', 1) else module.setShadowTransparency('All', 0.7) module.setButton('EndTurn', false) end

	if not model then return end
	model:Destroy()
	model = nil
end

function module.topMessage(text:string, textColor:Color3, delayTime:number)
	speechlabel.Text = text
	speechlabel.TextColor3 = textColor
	tweenService:Create(speechlabel, TweenInfo.new(0.1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {TextTransparency = 0}):Play()
	
	task.delay(delayTime or 0, function() tweenService:Create(speechlabel, TweenInfo.new(0.1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {TextTransparency = 1}):Play() end)
end

function module.setShadowTransparency(card:string, transparency:number)
	if card ~= 'All' then tweenService:Create(card.Shadow, TweenInfo.new(0.25, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {BackgroundTransparency = transparency}):Play() return end
	for _, cards in pairs(cardsFrame:GetChildren()) do
		if not cards:IsA('Frame') then continue end	
		tweenService:Create(cards.Shadow, TweenInfo.new(0.25, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {BackgroundTransparency = transparency}):Play()
	end
end

function module.updatePossibleCards()
	for _, slot in ipairs(deck:GetChildren()) do
		if not unit_data_holder[slot.Value] then continue end
		local data = unit_data_holder[slot.Value]
		if not playerUnits.List:FindFirstChild('B_'..slot.Value) then playerUnits.List:FindFirstChild('A_'..slot.Value).Limit.Text = 'Owned: '..(getUnitAmount(slot.Value)..'/'..data.Limit) continue end
		local button = playerUnits.List:FindFirstChild('B_'..slot.Value)
		button.Limit.Text = 'Owned: '..(getUnitAmount(slot.Value)..'/'..data.Limit)
		
		--print('you have', getUnitAmount(slot.Value), 'of', slot.Value)
		
		if getRound() < data.roundRequirement then
			button.RoundsLeft.Text = tostring((data.roundRequirement - getRound()))..' Rounds Left'
			continue
		else
			if getUnitAmount(slot.Value) >= data.Limit then
				button.ImageColor3 = Color3.fromRGB(150, 150, 150)
				button.Limit.TextColor3 = Color3.fromRGB(255, 0, 0)
				button.Blocked.Visible = true
			else
				button.ImageColor3 = Color3.fromRGB(255, 255, 255)
				button.Limit.TextColor3 = Color3.fromRGB(137, 255, 94)
				button.Blocked.Visible = false
			end
		end
		
		button.Name = string.gsub(button.Name, 'B_', 'A_')
		button.ImageColor3 = Color3.fromRGB(255, 255, 255)
		button.RoundsLeft.Text = 'Available!'
		button.RoundsLeft.TextColor3 = Color3.fromRGB(137, 255, 94)
		button.Blocked.Visible = false
	end
end

function module.loadPossibleCards()
	for _, slot in ipairs(deck:GetChildren()) do
		if not unit_data_holder[slot.Value] then continue end
		local data = unit_data_holder[slot.Value]
		local template = playerUnits.List.UnitTemplateSide:Clone()
		template.Parent = playerUnits.List
		template.Visible = true
		template.UnitName.Text = slot.Value
		template.Image = data.icon
		template.Limit.Text = 'Owned: '..(getUnitAmount(slot.Value)..'/'..data.Limit)
		
		template.MouseEnter:Connect(function()
			for __, k in pairs(template:GetDescendants()) do
				sounds.HoverSFX:Play()
				
				if k:IsA('TextLabel') then tweenService:Create(k, TweenInfo.new(0.3, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {TextTransparency = 0}):Play() end
				if k:IsA('UIStroke') and k.Parent:IsA('TextLabel') then tweenService:Create(k, TweenInfo.new(0.3, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {Transparency = 0}):Play() end
			end
		end)

		template.MouseLeave:Connect(function()
			for __, k in pairs(template:GetDescendants()) do
				if k:IsA('TextLabel') then tweenService:Create(k, TweenInfo.new(0.3, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {TextTransparency = 1}):Play() end
				if k:IsA('UIStroke') and k.Parent:IsA('TextLabel') then tweenService:Create(k, TweenInfo.new(0.3, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {Transparency = 1}):Play() end
			end
		end)
		
		if getUnitAmount(slot.Value) >= data.Limit then
			template.ImageColor3 = Color3.fromRGB(150, 150, 150)
			template.Limit.TextColor3 = Color3.fromRGB(255, 0, 0)
			template.Blocked.Visible = true
		else
			template.ImageColor3 = Color3.fromRGB(255, 255, 255)
			template.Limit.TextColor3 = Color3.fromRGB(137, 255, 94)
			template.Blocked.Visible = false
		end
		
		if getRound() < data.roundRequirement then
			template.ImageColor3 = Color3.fromRGB(150, 150, 150)
			template.RoundsLeft.Text = tostring((data.roundRequirement - getRound()))..' Rounds Left'
			template.Blocked.Visible = true
			template.Name = 'B_'..slot.Value
			continue
		end
		
		template.Name = 'A_'..slot.Value
		template.ImageColor3 = Color3.fromRGB(255, 255, 255)
		template.RoundsLeft.Text = 'Available!'
		template.RoundsLeft.TextColor3 = Color3.fromRGB(137, 255, 94)
		template.Blocked.Visible = false
	end
end

function module.tweenShadow(t:number)
	tweenService:Create(playerui:WaitForChild('Shadow').Shadow, TweenInfo.new(0.5, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {BackgroundTransparency = t}):Play()
end

function module.Message(color:Color3, text:string, win:boolean)
	local tween1 = tweenService:Create(matchEndLine, TweenInfo.new(0.8, Enum.EasingStyle.Cubic, Enum.EasingDirection.InOut), {Position = UDim2.new(0.5, 0,0.5, 0)})
	tween1:Play()

	tween1.Completed:Connect(function()
		task.wait(0.4)
		matchEndLine.TextL.TextColor3 = color
		textWritter(matchEndLine.TextL, text)
	end)

	if win == nil then return end
	if not win then
		task.wait(2)

		matchEndHud.Logs:Destroy()
		local tween1 = tweenService:Create(matchEndLine, TweenInfo.new(1, Enum.EasingStyle.Bounce, Enum.EasingDirection.Out), {Position = UDim2.new(0.495, 0,0.8, 0), Rotation = 10})
		tween1:Play()
		task.delay(0.55, function() sounds:WaitForChild('MetalPipe'):Play() sounds:WaitForChild('WompWompWomp'):Play() textWritter(matchEndLine.TextL, losingTexts[math.random(1, #losingTexts)]) end)
	else
		sounds:WaitForChild('Win'):Play()
		for i=1, AmountOfConfetti do
			local p = ConfettiCannon.createParticle(
				Vector2.new((math.random(1, 10)/10),1), 									-- Position on screen. (Scales)
				Vector2.new(math.random(90)-45, math.random(70,100)), 		-- The direction power of the blast.
				matchEndHud:WaitForChild('ConfettiFrame'), 												-- The frame that these should be displayed on.
				{Color3.fromRGB(255,255,100), Color3.fromRGB(255,100,100), Color3.fromRGB(164, 74, 255), Color3.fromRGB(41, 255, 8), Color3.fromRGB(255, 0, 144)} 	-- The colors that should be used.
			);
			table.insert(confetti, p);
		end
		
		sounds:WaitForChild('Confetti'):Play()
		sounds:WaitForChild('Pop'):Play()

		confettiColors = {Color3.fromRGB(255,255,100), Color3.fromRGB(255,100,100), Color3.fromRGB(164, 74, 255), Color3.fromRGB(41, 255, 8), Color3.fromRGB(255, 0, 144)};
		confettiActive = true

		task.wait(2)

		createNewLog(Color3.fromRGB(255, 140, 0), '+350 Coins')
		confettiActive = false
	end
end

function module.setModel()
	if placing == nil then highlight.Parent = script return end
	if not collection:FindFirstChild(placing) then warn(placing, 'is not on the collection') return end
	local unitVal = collection:WaitForChild(placing)
	if not units:FindFirstChild(placing) then warn(placing, 'does not exist') return end
	if not units:WaitForChild(placing):FindFirstChild(unitVal.Value) then warn(unitVal.Value, 'is not a valid skin for', placing) return end
	local skin = units:WaitForChild(placing):FindFirstChild(unitVal.Value)
	
	model = skin:WaitForChild('Model'):Clone()
	model.Parent = camera
	model.PrimaryPart.CFrame = mouse.Target.CFrame * CFrame.new(0, 2.3, 0)
	mouse.TargetFilter = model
	
	--arrow.Parent = camera
	--arrow.CFrame = mouse.Target.CFrame * CFrame.new(0, 6, 0) * CFrame.Angles(0, math.rad(90), math.rad(-90))

	if not model:FindFirstChild('Idle') then return end
	model:WaitForChild('Humanoid').Animator:LoadAnimation(model:FindFirstChild('Idle')):Play()

	for _, parts in pairs(model:GetChildren()) do
		if not parts:IsA('BasePart') or not parts:IsA('MeshPart') then continue end
		parts.Transparency = 1
	end
end

function module.plusStud(amount:number)
	local plusStud = gameHud:WaitForChild('PlusStud'):Clone()
	plusStud.Studs.Text = '+'..amount
	plusStud.Parent = gameHud
	plusStud.Visible = true
	plusStud:TweenSize(UDim2.new(0.072, 0, 0.084, 0), Enum.EasingDirection.In, Enum.EasingStyle.Back, 0.25)
	
	task.delay(0.7, function()
		plusStud:TweenSizeAndPosition(gameHud:WaitForChild('Studs').Size, gameHud:WaitForChild('Studs').Position, Enum.EasingDirection.In, Enum.EasingStyle.Back, 0.4)
		
		task.wait(0.4)
		sounds.Cash:Play()
		plusStud:Destroy()
		gameHud:WaitForChild('Studs').Studs.Text = getStuds()
		gameHud:WaitForChild('Studs').Studs.TextStrokeColor3 = Color3.fromRGB(255,255,255)
		gameHud:WaitForChild('Studs').Studs.Position = UDim2.new(0, 0, -0.15, 0)
		gameHud:WaitForChild('Studs').Studs:TweenPosition(UDim2.new(0,0,0,0), Enum.EasingDirection.Out, Enum.EasingStyle.Sine, 0.25, true)
		tweenService:Create(gameHud:WaitForChild('Studs').Studs, TweenInfo.new(0.25, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {TextStrokeColor3 = Color3.fromRGB(0,0,0)}):Play()
	end)
end

function module.positionateCameras()
	for _, values in pairs(arenasFolder:GetChildren()) do
		if not values:IsA('StringValue') then continue end
		if not values.Name:match('Player') then continue end
		if values.Value ~= player.Name then continue end
		local cameraTween = tweenService:Create(camera, TweenInfo.new(0.2, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {CFrame = values.Parent:FindFirstChild(values.Name..'_Camera').Normal.Value})
		cameraTween:Play()
	end
end

function module.moveCamera(pos:string)
	for _, values in pairs(arenasFolder:GetChildren()) do
		if not values:IsA('StringValue') then continue end
		if not string.find(values.Name, 'Player') then continue end
		if values.Value ~= player.Name then continue end
		
		local cameraTween = tweenService:Create(camera, TweenInfo.new(0.35, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {CFrame = values.Parent:FindFirstChild(values.Name..'_Camera'):WaitForChild(pos).Value})
		cameraTween:Play()
	end
end

function module.prepareBoard()
--	task.wait(10)
	for _, tiles in pairs(arenasFolder.Map[MapName]:WaitForChild('Tiles'):GetDescendants()) do
		if not tiles:IsA('Part') then continue end
		if tiles.Transparency == 0 then continue end
		local tween = tweenService:Create(tiles, TweenInfo.new(0.3, Enum.EasingStyle.Back, Enum.EasingDirection.Out), {Transparency = 0})
		tween:Play()
		task.wait(0.1)
	end
end

function module.playSong()
	local song = getRandomSong()
	gameHud:WaitForChild('MusicPlaying'):TweenPosition(UDim2.new(0.16, 0,0.947, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 3, true)
	gameHud:WaitForChild('MusicPlaying').Text = 'Now Playing: '..song.Creator..' - '..song.MusicName
	task.delay(5, function() gameHud:WaitForChild('MusicPlaying'):TweenPosition(UDim2.new(-1, 0,0.947, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 3, true) end)
	sounds:WaitForChild('BGMusic').SoundId = song.ID
	sounds:WaitForChild('BGMusic'):Play()
end

function module.matchEnd()
	gameHud.Enabled = false
	sounds:WaitForChild('BGMusic').Volume = 0
	sounds:WaitForChild('MatchEnd'):Play()

	local imgTween1 = tweenService:Create(matchEndHud:WaitForChild('MatchEnd'), TweenInfo.new(0.4, Enum.EasingStyle.Linear), {ImageTransparency = 0, Size = UDim2.new(0, 700, 0, 430)})
	imgTween1:Play()

	task.spawn(function()
		sounds:WaitForChild('Change'):Play()
		for i = 1, 10 do
			matchEndHud:WaitForChild('MatchEnd').Rotation = math.random(-3, 3)
			task.wait(0.01)
		end
		matchEndHud:WaitForChild('MatchEnd').Rotation = 0
	end)

	imgTween1.Completed:Connect(function()
		task.wait(2)
		local imgTween2 = tweenService:Create(matchEndHud:WaitForChild('MatchEnd'), TweenInfo.new(0.4, Enum.EasingStyle.Quad, Enum.EasingDirection.In), {Position = UDim2.new(0.5, 0, 2, 0)})
		imgTween2:Play() imgTween2.Completed:Wait()
		if character:WaitForChild('HP').Value < 1 then module.Message(Color3.fromRGB(255, 70, 70), 'You Lose...', false) return else sounds:WaitForChild('WinMusic'):Play() module.Message(Color3.fromRGB(255, 217, 0), 'yay you won', true) end
	end)
end

turn.Changed:Connect(function()
	task.spawn(function() sounds:WaitForChild('Change'):Play()
		for i = 1, 10 do
			gameHud:WaitForChild('Turn').Rotation = math.random(-3, 3)
			task.wait(0.01)
		end	gameHud:WaitForChild('Turn').Rotation = 0
	end)

	--// Update card colors
	if getTurn() ~= player.Name then setTransparencyEnemy(1) module.setButton('Destroy', false) module.setButton('EndTurn', false) module.setShadowTransparency('All', 0.7) module.cancelPlacing(false) else setTransparencyEnemy(1) module.setShadowTransparency('All', 1) module.setButton('EndTurn', true) end
	if getTurn() ~= 'Action' then gameHud:WaitForChild('Turn').Text = getTurn()..'\'s turn' else setTransparencyEnemy(0) gameHud:WaitForChild('Turn').Text = 'Units in action...' module.setShadowTransparency('All', 0.7) end
	
	--// Update Unit Cost
	task.wait(0.01)
	buyCards:WaitForChild("Studs").Studs.Text = arenasFolder.UnitCost.Value
	buyCards:WaitForChild('Studs').Studs.TextStrokeColor3 = Color3.fromRGB(255,255,255)
	buyCards:WaitForChild('Studs').Studs.Position = UDim2.new(0, 0, -0.15, 0)
	buyCards:WaitForChild('Studs').Studs:TweenPosition(UDim2.new(0,0,0,0), Enum.EasingDirection.Out, Enum.EasingStyle.Sine, 0.25, true)
	tweenService:Create(buyCards:WaitForChild('Studs').Studs, TweenInfo.new(0.25, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {TextStrokeColor3 = Color3.fromRGB(0,0,0)}):Play()
end)

repeat task.wait() until gameHud.Enabled == true

mouse.Move:Connect(function()
	if placing ~= nil then return end
	module.showInfo()
end)

--// MAKE UNITS ADDED INVISIBLE
local function doUnitTransparency(targetModel:Model)
	for _, part in ipairs(targetModel:GetDescendants()) do
		if part:IsA('BasePart') or part:IsA('Decal') then part.Transparency = 1 end
		if part:IsA('Beam') then part.Enabled = false end
	end
end

local map = arenasFolder.Map:FindFirstChildOfClass('Folder')
local tiles = map:FindFirstChild('Tiles')
local enemyTiles;

repeat task.wait() until arenasFolder.Player1.Value ~= 'None' and arenasFolder.Player2.Value ~= 'None'
task.wait(0.5)

for __, x in pairs(arenasFolder:GetChildren()) do
	if not x:IsA('StringValue') then continue end
	if not string.find(x.Name, 'Player') then continue end
	if x.Value == player.Name then continue end
	enemyTiles = tiles[x.Value]
	break
end

if enemyTiles then
	enemyTiles.DescendantAdded:Connect(function(descendant:Instance)
		if not descendant.Parent:FindFirstChild('OccupiedBy') then return end
		if getTurn() == 'Action' then return end
		
		if descendant:IsA('Model') then doUnitTransparency(descendant) end
		if descendant.Name == 'TileGlow' then
			for _, x in pairs(descendant:GetChildren()) do
				if x:IsA('Beam') then x.Enabled = false end
				if x:IsA('Sound') then x.Volume = 0 end
				if x:IsA('ParticleEmitter') then
					x.Transparency = NumberSequence.new({
						NumberSequenceKeypoint.new(0, 1);
						NumberSequenceKeypoint.new(1, 1);
					})
				end
			end
		end
	end)
end

--// CHECK POSSIBLE UNITS
arenasFolder.Round.Changed:Connect(module.updatePossibleCards)

--// HP CHECK
character:WaitForChild('HP').Changed:Connect(function()
	if getHP() <= 5 then
		if not sounds.Heartbeat.IsPlaying then
			sounds.Heartbeat:Play()
			tweenService:Create(playerui:WaitForChild('Shadow').LowHP, TweenInfo.new(1.5, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {ImageTransparency = 0.8}):Play()
			tweenService:Create(gameHud.Health.HP, TweenInfo.new(1.5, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {TextColor3 = Color3.fromRGB(255, 82, 82)}):Play()
			tweenService:Create(gameHud.Health, TweenInfo.new(0.8, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, math.huge, true), {Size = UDim2.new(0.064, 0, 0.08, 0)}):Play()	
		end
	end
end)

--// RS
runService.RenderStepped:Connect(function(deltaTime:number)
	if arenasFolder:FindFirstChild(player.Name..'_Fog') then
		arenasFolder[player.Name..'_Fog']:Destroy()
	end
	
	if userInputService.TouchEnabled then
		if playerui.TouchGui.TouchControlFrame:FindFirstChild("DynamicThumbstickFrame") then
			playerui.TouchGui.TouchControlFrame.DynamicThumbstickFrame:Destroy()
		end
	end
	
	for _,val in pairs(confetti) do
		if (confettiColors) then val:SetColors(confettiColors) end
		val.Enabled = confettiActive
		val:Update()
	end
	
	if arenasFolder.Turn.Value ~= player.Name then return end
	if onSettings then return end
	if placing == nil and not onSettings then highlight.Parent = script return end
	if not mouse.Target then return end
	if mouse.Target.Parent.Parent.Name ~= 'Tiles' then return end
	if mouse.Target.Parent.Name ~= player.Name then return end
	if not mouse.Target:FindFirstChild('OccupiedBy') then return end
	if highlight.Parent ~= mouse.Target then if tile then sounds:WaitForChild('HoverSFX'):Play() end end
	if not mouse.Target:FindFirstChild('Hover') then highlight.Parent = mouse.Target end
	if not model then module.setModel() return end
	model.PrimaryPart.CFrame = mouse.Target.CFrame * CFrame.new(0, 2.3, 0)
	
	if mouse.Target:WaitForChild('OccupiedBy').Value == 'None' then highlight.FillColor = Color3.new(0.827451, 1, 0.815686); tile = mouse.Target; return end --arrow.Color = Color3.fromRGB(81, 255, 0)
	highlight.FillColor = Color3.new(1, 0.454902, 0.454902); tile = nil; --arrow.Color = Color3.fromRGB(255, 0, 4)
end)

return module

update this function to

local function moveFrameBasedOnRotation(frame, angle, distance)
    local radians = math.rad(angle)
    local deltaX = math.cos(radians) * distance
    local deltaY = math.sin(radians) * distance
    frame.Position = UDim2.new(
        frame.Position.X.Scale, 
        frame.Position.X.Offset + deltaX,
        frame.Position.Y.Scale, 
        frame.Position.Y.Offset + deltaY
    )
end

right now in handlemouseenter for example

moveFrameBasedOnRotation(k, k.Rotation, 10)

and handlemouseleave

moveFrameBasedOnRotation(k, k.Rotation, -10)

and cancelplacing

moveFrameBasedOnRotation(selectedButton, selectedButton.Rotation, -20)

you need to adjust them though let me know if there’s any issue