Make custom proximity prompt appear forever

I found a custom proximity prompt script and i want that the prompt is forever there no matter if the player is near it or not looking at it, just make it appear forever, and interactable and with no animations just make it appear forever as if its just a normal gui hovering above something


local UserInputService = game:GetService("UserInputService")
local ProximityPromptService = game:GetService("ProximityPromptService")
local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local localPlayer = Players.LocalPlayer

local playerGui = localPlayer:WaitForChild("PlayerGui")
local customPrompt = ReplicatedStorage:WaitForChild("NewPrompt")

--Imags configs
local GamepadButtonImage = {
	[Enum.KeyCode.ButtonX] = "http://www.roblox.com/asset/?id=429501348",
	[Enum.KeyCode.ButtonY] = "http://www.roblox.com/asset/?id=429501346",
	[Enum.KeyCode.ButtonA] = "http://www.roblox.com/asset/?id=429479022",
	[Enum.KeyCode.ButtonB] = "http://www.roblox.com/asset/?id=429501329",
	[Enum.KeyCode.DPadLeft] = "rbxasset://textures/ui/Controls/dpadLeft.png",
	[Enum.KeyCode.DPadRight] = "rbxasset://textures/ui/Controls/dpadRight.png",
	[Enum.KeyCode.DPadUp] = "rbxasset://textures/ui/Controls/dpadUp.png",
	[Enum.KeyCode.DPadDown] = "rbxasset://textures/ui/Controls/dpadDown.png",
	[Enum.KeyCode.ButtonSelect] = "rbxasset://textures/ui/Controls/xboxmenu.png",
	[Enum.KeyCode.ButtonL1] = "http://www.roblox.com/asset/?id=429501340",
	[Enum.KeyCode.ButtonR1] = "http://www.roblox.com/asset/?id=429501341",
	[Enum.KeyCode.ButtonL2] = "http://www.roblox.com/asset/?id=429501325",
	[Enum.KeyCode.ButtonR2] = "http://www.roblox.com/asset/?id=429501338",
}

local KeyboardButtonImage = {
	[Enum.KeyCode.Backspace] = "rbxasset://textures/ui/Controls/backspace.png",
	[Enum.KeyCode.Return] = "rbxasset://textures/ui/Controls/return.png",
	[Enum.KeyCode.LeftShift] = "rbxasset://textures/ui/Controls/shift.png",
	[Enum.KeyCode.RightShift] = "rbxasset://textures/ui/Controls/shift.png",
	[Enum.KeyCode.Tab] = "rbxasset://textures/ui/Controls/tab.png",
}

local KeyboardButtonIconMapping = {
	["'"] = "rbxasset://textures/ui/Controls/apostrophe.png",
	[","] = "rbxasset://textures/ui/Controls/comma.png",
	["`"] = "rbxasset://textures/ui/Controls/graveaccent.png",
	["."] = "rbxasset://textures/ui/Controls/period.png",
	[" "] = "rbxasset://textures/ui/Controls/spacebar.png",
}

local MscIconMapping = {
	["TouchTapIcon"] = "rbxasset://textures/ui/Controls/TouchTapIcon.png",
	["key_single"] = "http://www.roblox.com/asset/?id=7310154850",
	
	--The commented out original dosent fit well at all
	--["key_single"] = "rbxasset://textures/ui/Controls/key_single.png",
}
--Added this option in just incase the key icon arround letters is unwanted
local ShowOutlineForStanderdKeys = true

local KeyCodeToTextMapping = {
	[Enum.KeyCode.LeftControl] = "Ctrl",
	[Enum.KeyCode.RightControl] = "Ctrl",
	[Enum.KeyCode.LeftAlt] = "Alt",
	[Enum.KeyCode.RightAlt] = "Alt",
	[Enum.KeyCode.F1] = "F1",
	[Enum.KeyCode.F2] = "F2",
	[Enum.KeyCode.F3] = "F3",
	[Enum.KeyCode.F4] = "F4",
	[Enum.KeyCode.F5] = "F5",
	[Enum.KeyCode.F6] = "F6",
	[Enum.KeyCode.F7] = "F7",
	[Enum.KeyCode.F8] = "F8",
	[Enum.KeyCode.F9] = "F9",
	[Enum.KeyCode.F10] = "F10",
	[Enum.KeyCode.F11] = "F11",
	[Enum.KeyCode.F12] = "F12",
}
 
--If sound effects are wanted, configer in the sound parented to this script
local PopupAudioEnabeld = true
local TriggerdAudioEnabeld = true

-- for animaiton
function Lerp(a, b, t)
	return a + (b - a) * t
end


local function getScreenGui()
	local screenGui = playerGui:FindFirstChild("ProximityPrompts")
	if screenGui == nil then
		screenGui = Instance.new("ScreenGui")
		screenGui.Name = "ProximityPrompts"
		screenGui.ResetOnSpawn = false
		screenGui.Parent = playerGui
	end
	return screenGui
end

local function createPrompt(prompt, inputType, gui)
	
	-- ui items and locations
	local promptUI = customPrompt:Clone()
	local InputFrame = promptUI:WaitForChild("InputFrame")
	local TouchBox = InputFrame:WaitForChild("TouchBox")
	local ProgressFrame = InputFrame:WaitForChild("ProgressFrame")
	local InputIcon = InputFrame:WaitForChild("InputIcon")
	local InputText = InputFrame:WaitForChild("InputText")

	local DiscriptionFrame = promptUI:WaitForChild("DiscriptionFrame")
	local ActionText = DiscriptionFrame:WaitForChild("ActionText")
	local ObjectText = DiscriptionFrame:WaitForChild("ObjectText")
	
	--Offset config
	promptUI.SizeOffset = Vector2.new(
		prompt.UIOffset.X / promptUI.Size.Width.Offset,
		prompt.UIOffset.Y / promptUI.Size.Height.Offset
	)
	
	--Animations Configs
	
	--Prompt Hide/Show Animation config	
	local tweenInfoFast = TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
	--Make the tabels of objects to be tweened during the Hide/Show Animation
	local textTable = {ActionText, InputText, ObjectText}
	local imageTable = {InputIcon}
	local frameTable = {InputFrame, DiscriptionFrame}
	
	
	--Hold Animation configs \/
	--the tween info for the aniamation tween needs to be here due to the aniation time caculations			
	local AnimeTweenInfo = TweenInfo.new(prompt.HoldDuration, Enum.EasingStyle.Quart, Enum.EasingDirection.Out)
	--make the tweens outside of the loop to not have tweens overlaping and so tweens can be canseled by early realece of hold
	local HoldTween1 = TweenService:Create(ProgressFrame, AnimeTweenInfo, {Size = InputFrame.Size})

	---------------------------------------------------------------------------------------------------------------------------
	---------------------------------------------------------------------------------------------------------------------------
	---------------------------------------------------------------------------------------------------------------------------
	---------------------------------------------------------------------------------------------------------------------------
	
	if PopupAudioEnabeld == false then
		script.PopupAudio.Volume = 0
	end
	if TriggerdAudioEnabeld == false then
		script.TriggerdAudio.Volume = 0
	end
	
	-- Updates the cloned prompt to match the information in the ProximityPrompt in workspace
	local function updateUIFromPrompt()
		ActionText.Text = prompt.ActionText
		ObjectText.Text = prompt.ObjectText

		
		-- Set the input button to the correct input based on the user platform
		if inputType == Enum.ProximityPromptInputType.Gamepad then
			if GamepadButtonImage[prompt.GamepadKeyCode] then
				InputIcon.Image = GamepadButtonImage[prompt.GamepadKeyCode]
			end
		elseif inputType == Enum.ProximityPromptInputType.Touch then
			InputIcon.Image = MscIconMapping["TouchTapIcon"]
		else
			if ShowOutlineForStanderdKeys == true then
				InputIcon.Image = MscIconMapping["key_single"]
			end
			local buttonTextString = UserInputService:GetStringForKeyCode(prompt.KeyboardKeyCode)

			-- Set buttonTextImage to an image if the KeyboardKeyCode is not representable with a character
			-- Get image representation for Backspace, Return, Tab, Shift
			local buttonTextImage = KeyboardButtonImage[prompt.KeyboardKeyCode]
			if buttonTextImage == nil then
				-- Get image representation for apostrophe, comma, graveaccent, period, spacebar
				buttonTextImage = KeyboardButtonIconMapping[buttonTextString]
			end

			-- Set buttonTextString to a string if the KeyboardKeyCode doesn't have a direct character match
			-- Get string representation for Ctrl, Alt, and function keys
			if buttonTextImage == nil then
				local keyCodeMappedText = KeyCodeToTextMapping[prompt.KeyboardKeyCode]
				if keyCodeMappedText then
					buttonTextString = keyCodeMappedText
				end
			end 

			-- Set the UI ButtonImage or the UI ButtonText
			if buttonTextImage then
				InputIcon.Image = buttonTextImage
			elseif buttonTextString ~= nil and buttonTextString ~= '' then
				InputText.Text = buttonTextString
			else
				InputText.Visible = false
				error("ProximityPrompt '" .. prompt.Name .. "' has an unsupported keycode for rendering UI: " .. tostring(prompt.KeyboardKeyCode))
			end
		end
		
	end
	updateUIFromPrompt()
	
	
	--Sets Up tweens
	
	-- Tween Variables
	local tweensForFadeOut = {}
	local tweensForFadeIn = {}
	local InputTweensForFadeOut = {}
	local InputTweensForFadeIn = {}
	
	-- Text Tweens
	for _, object in ipairs(textTable) do
		if object == InputText then
			table.insert(InputTweensForFadeOut, TweenService:Create(object, tweenInfoFast, { TextTransparency = 1 }))
			table.insert(InputTweensForFadeIn, TweenService:Create(object, tweenInfoFast, { TextTransparency = object.TextTransparency }))
		else
			table.insert(tweensForFadeOut, TweenService:Create(object, tweenInfoFast, { TextTransparency = 1 }))
			table.insert(tweensForFadeIn, TweenService:Create(object, tweenInfoFast, { TextTransparency = object.TextTransparency }))
		end
	end
	
	-- Frame Tweens
	for _, object in ipairs(frameTable) do
		if object == InputFrame then
			table.insert(InputTweensForFadeOut, TweenService:Create(object, tweenInfoFast, { Size = UDim2.fromScale(0, 1), BackgroundTransparency = 1, Visible = false }))
			table.insert(InputTweensForFadeIn, TweenService:Create(object, tweenInfoFast, { Size = UDim2.fromScale(1, 1), BackgroundTransparency = object.BackgroundTransparency, Visible = true }))
		else
			table.insert(tweensForFadeOut, TweenService:Create(object, tweenInfoFast, { Size = UDim2.fromScale(0, 1), BackgroundTransparency = 1, Visible = false }))
			table.insert(tweensForFadeIn, TweenService:Create(object, tweenInfoFast, { Size = UDim2.fromScale(1, 1), BackgroundTransparency = object.BackgroundTransparency, Visible = true }))
		end
	end

	-- Image Tweens
	for _, object in ipairs(imageTable) do
		if object == InputIcon then
			table.insert(InputTweensForFadeOut, TweenService:Create(object, tweenInfoFast, {BackgroundTransparency = 1, ImageTransparency = 1, Visible = false }))
			table.insert(InputTweensForFadeIn, TweenService:Create(object, tweenInfoFast, {BackgroundTransparency = object.BackgroundTransparency, ImageTransparency = object.ImageTransparency, Visible = true }))
		else
			table.insert(tweensForFadeOut, TweenService:Create(object, tweenInfoFast, {BackgroundTransparency = 1, ImageTransparency = 1, Visible = false }))
			table.insert(tweensForFadeIn, TweenService:Create(object, tweenInfoFast, {BackgroundTransparency = object.BackgroundTransparency, ImageTransparency = object.ImageTransparency, Visible = true }))
		end
	end
	
	
	--reset the prompt for intial config (make complex latter as core needs to be made first)
	DiscriptionFrame.Size = UDim2.fromScale(0, 1)
	DiscriptionFrame.BackgroundTransparency = 1
	DiscriptionFrame.Visible = false
	ObjectText.TextTransparency = 1
	ActionText.TextTransparency = 1
	InputIcon.ImageTransparency = 1

	--Opning animation play (So the First thing the proompt does) and play sound (will not have audio if set to false)
	script.PopupAudio:Play()
	for _, tween in ipairs(tweensForFadeIn) do
		tween:Play()
	end
	for _, tween in ipairs(InputTweensForFadeIn) do
		tween:Play()
	end
	
	local loop = true

	--Hold Animaiton Function
	local HoldAnimation = function()
		local initalT = tick()
		local deltaT = 0
		local Tweened = false
		--Find tween info in above
		while(deltaT < prompt.HoldDuration and loop == true) do
			game:GetService("RunService").Stepped:wait()

			--tween olny once per animaton
			if Tweened == false then
				Tweened = true
				HoldTween1:Play()
			end
			
			--Time delta for lerp | the lerp used here takes timve values between 0 (not started) to 1 (finished)
			deltaT = tick() - initalT
			
			--eventualy makt the aniamtion less jaged, if tween is posible (it is for udim2 but not udim)
			--udim lerp
			ProgressFrame.UICorner.CornerRadius = UDim.new(InputFrame.UICorner.CornerRadius.Scale, Lerp(60,InputFrame.UICorner.CornerRadius.Offset,deltaT/prompt.HoldDuration)) 
			--ProgressFrame.Size = UDim2.new(Lerp(0, InputFrame.Size.X.Scale ,deltaT/prompt.HoldDuration) ,0,InputFrame.Size.Y.Scale ,0) 
			
		end
		HoldTween1:Cancel()
		loop = true
		Tweened = false
		ProgressFrame.Size = UDim2.new(0,0,InputFrame.Size.Y.Scale ,0)
		ProgressFrame.UICorner.CornerRadius = UDim.new(InputFrame.UICorner.CornerRadius.Scale,60)
	end 
	
	
	-- Handles Click/Touch input
	if inputType == Enum.ProximityPromptInputType.Touch or prompt.ClickablePrompt then
		local button = TouchBox
		local buttonDown = false
		button.InputBegan:Connect(function(input)
			if (input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1) and
				input.UserInputState ~= Enum.UserInputState.Change then
				prompt:InputHoldBegin()
				buttonDown = true				
			end
		end)
		button.InputEnded:Connect(function(input)
			if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then
				if buttonDown then
					buttonDown = false
					prompt:InputHoldEnd()
				end
			end
		end)

		promptUI.Active = true
	end
	
	
	--runs Hold Animaiton
	local AnimeRoutean = coroutine.create(HoldAnimation)
	prompt.PromptButtonHoldBegan:Connect(function()
		
		loop = true
		AnimeRoutean = coroutine.create(HoldAnimation)
		coroutine.resume(AnimeRoutean)
		
		--hide all but the key button
		for _, tween in ipairs(tweensForFadeOut) do
			tween:Play()
		end
		
	end)
	
	prompt.PromptButtonHoldEnded:Connect(function()
		loop = false
		for _, tween in ipairs(tweensForFadeIn) do
			tween:Play()
		end
		HoldTween1:Cancel()
		coroutine.yield(AnimeRoutean)
		
	end)
	
	--reloads to accomidate switching from contrler to keayboard and vice versa
	local lastInputType = Enum.UserInputType.Keyboard

	UserInputService.InputChanged:Connect(function(input, gameProcessed)
		if input.UserInputType == Enum.UserInputType.Keyboard and lastInputType ~= input.UserInputType then
			lastInputType = input.UserInputType
			updateUIFromPrompt()
		elseif input.UserInputType == Enum.UserInputType.Touch and lastInputType ~= input.UserInputType then
			lastInputType = input.UserInputType
			updateUIFromPrompt()
		elseif input.UserInputType == Enum.UserInputType.Gamepad1 and lastInputType ~= input.UserInputType then
			lastInputType = input.UserInputType
			updateUIFromPrompt()
		end

	end)

	
	
	-- Variables for event connections
	local triggeredConnection
	local triggerEndedConnection

	-- Connect to events to play tweens when Triggered/Ended
	triggeredConnection = prompt.Triggered:Connect(function()
		for _, tween in ipairs(tweensForFadeOut) do
			tween:Play()
		end
		for _, tween in ipairs(InputTweensForFadeOut) do
			tween:Play()
		end
		script.TriggerdAudio:Play()
	end)       

	triggerEndedConnection = prompt.TriggerEnded:Connect(function()
		for _, tween in ipairs(tweensForFadeIn) do
			tween:Play()
		end
		for _, tween in ipairs(InputTweensForFadeIn) do
			tween:Play()
		end
	end)
	
	-- Make the Prompt actually show up on screen
	promptUI.Adornee = prompt.Parent
	promptUI.Parent = gui
	for _, tween in ipairs(tweensForFadeIn) do
		tween:Play()
	end
	for _, tween in ipairs(InputTweensForFadeIn) do
		tween:Play()
	end
	
	local function cleanupFunction()
		triggeredConnection:Disconnect()
		triggerEndedConnection:Disconnect()
		for _, tween in ipairs(tweensForFadeOut) do
			tween:Play()
		end
		for _, tween in ipairs(InputTweensForFadeOut) do
			tween:Play()
		end
		wait(0.2)
		promptUI.Parent = nil
	end
	return cleanupFunction
end

ProximityPromptService.PromptShown:Connect(function(prompt, inputType)
	if prompt.Style == Enum.ProximityPromptStyle.Default then
		return
	end
	local gui = getScreenGui()	
	local cleanupFunction = createPrompt(prompt, inputType, gui)
	prompt.PromptHidden:Wait()
	cleanupFunction()
end) 

i want it to appear forever because something in the script just checks for a humanoid constantly or something, and that makes my game lag like alot

also its a script that replaces the normal proximity prompts, just so you know

1 Like

I could be wrong, but I think there is an option where it changes the distance at which the proximity prompt appears, maybe you can change that