ProximityPromptStyle

Code Samples

Generating a Custom Proximity Prompt

1local UserInputService = game:GetService("UserInputService")
2local ProximityPromptService = game:GetService("ProximityPromptService")
3local TweenService = game:GetService("TweenService")
4local TextService = game:GetService("TextService")
5local Players = game:GetService("Players")
6
7local LocalPlayer = Players.LocalPlayer
8
9local PlayerGui = LocalPlayer:WaitForChild("PlayerGui")
10
11local GamepadButtonImage = {
12 [Enum.KeyCode.ButtonX] = "rbxasset://textures/ui/Controls/xboxX.png",
13 [Enum.KeyCode.ButtonY] = "rbxasset://textures/ui/Controls/xboxY.png",
14 [Enum.KeyCode.ButtonA] = "rbxasset://textures/ui/Controls/xboxA.png",
15 [Enum.KeyCode.ButtonB] = "rbxasset://textures/ui/Controls/xboxB.png",
16 [Enum.KeyCode.DPadLeft] = "rbxasset://textures/ui/Controls/dpadLeft.png",
17 [Enum.KeyCode.DPadRight] = "rbxasset://textures/ui/Controls/dpadRight.png",
18 [Enum.KeyCode.DPadUp] = "rbxasset://textures/ui/Controls/dpadUp.png",
19 [Enum.KeyCode.DPadDown] = "rbxasset://textures/ui/Controls/dpadDown.png",
20 [Enum.KeyCode.ButtonSelect] = "rbxasset://textures/ui/Controls/xboxmenu.png",
21 [Enum.KeyCode.ButtonL1] = "rbxasset://textures/ui/Controls/xboxLS.png",
22 [Enum.KeyCode.ButtonR1] = "rbxasset://textures/ui/Controls/xboxRS.png",
23}
24
25local KeyboardButtonImage = {
26 [Enum.KeyCode.Backspace] = "rbxasset://textures/ui/Controls/backspace.png",
27 [Enum.KeyCode.Return] = "rbxasset://textures/ui/Controls/return.png",
28 [Enum.KeyCode.LeftShift] = "rbxasset://textures/ui/Controls/shift.png",
29 [Enum.KeyCode.RightShift] = "rbxasset://textures/ui/Controls/shift.png",
30 [Enum.KeyCode.Tab] = "rbxasset://textures/ui/Controls/tab.png",
31}
32
33local KeyboardButtonIconMapping = {
34 ["'"] = "rbxasset://textures/ui/Controls/apostrophe.png",
35 [","] = "rbxasset://textures/ui/Controls/comma.png",
36 ["`"] = "rbxasset://textures/ui/Controls/graveaccent.png",
37 ["."] = "rbxasset://textures/ui/Controls/period.png",
38 [" "] = "rbxasset://textures/ui/Controls/spacebar.png",
39}
40
41local KeyCodeToTextMapping = {
42 [Enum.KeyCode.LeftControl] = "Ctrl",
43 [Enum.KeyCode.RightControl] = "Ctrl",
44 [Enum.KeyCode.LeftAlt] = "Alt",
45 [Enum.KeyCode.RightAlt] = "Alt",
46 [Enum.KeyCode.F1] = "F1",
47 [Enum.KeyCode.F2] = "F2",
48 [Enum.KeyCode.F3] = "F3",
49 [Enum.KeyCode.F4] = "F4",
50 [Enum.KeyCode.F5] = "F5",
51 [Enum.KeyCode.F6] = "F6",
52 [Enum.KeyCode.F7] = "F7",
53 [Enum.KeyCode.F8] = "F8",
54 [Enum.KeyCode.F9] = "F9",
55 [Enum.KeyCode.F10] = "F10",
56 [Enum.KeyCode.F11] = "F11",
57 [Enum.KeyCode.F12] = "F12",
58}
59
60local function getScreenGui()
61 local screenGui = PlayerGui:FindFirstChild("ProximityPrompts")
62 if screenGui == nil then
63 screenGui = Instance.new("ScreenGui")
64 screenGui.Name = "ProximityPrompts"
65 screenGui.ResetOnSpawn = false
66 screenGui.Parent = PlayerGui
67 end
68 return screenGui
69end
70
71local function createProgressBarGradient(parent, leftSide)
72 local frame = Instance.new("Frame")
73 frame.Size = UDim2.fromScale(0.5, 1)
74 frame.Position = UDim2.fromScale(leftSide and 0 or 0.5, 0)
75 frame.BackgroundTransparency = 1
76 frame.ClipsDescendants = true
77 frame.Parent = parent
78
79 local image = Instance.new("ImageLabel")
80 image.BackgroundTransparency = 1
81 image.Size = UDim2.fromScale(2, 1)
82 image.Position = UDim2.fromScale(leftSide and 0 or -1, 0)
83 image.Image = "rbxasset://textures/ui/Controls/RadialFill.png"
84 image.Parent = frame
85
86 local gradient = Instance.new("UIGradient")
87 gradient.Transparency = NumberSequence.new({
88 NumberSequenceKeypoint.new(0, 0),
89 NumberSequenceKeypoint.new(0.4999, 0),
90 NumberSequenceKeypoint.new(0.5, 1),
91 NumberSequenceKeypoint.new(1, 1),
92 })
93 gradient.Rotation = leftSide and 180 or 0
94 gradient.Parent = image
95
96 return gradient
97end
98
99local function createCircularProgressBar()
100 local bar = Instance.new("Frame")
101 bar.Name = "CircularProgressBar"
102 bar.Size = UDim2.fromOffset(58, 58)
103 bar.AnchorPoint = Vector2.new(0.5, 0.5)
104 bar.Position = UDim2.fromScale(0.5, 0.5)
105 bar.BackgroundTransparency = 1
106
107 local gradient1 = createProgressBarGradient(bar, true)
108 local gradient2 = createProgressBarGradient(bar, false)
109
110 local progress = Instance.new("NumberValue")
111 progress.Name = "Progress"
112 progress.Parent = bar
113 progress.Changed:Connect(function(value)
114 local angle = math.clamp(value * 360, 0, 360)
115 gradient1.Rotation = math.clamp(angle, 180, 360)
116 gradient2.Rotation = math.clamp(angle, 0, 180)
117 end)
118
119 return bar
120end
121
122local function createPrompt(prompt, inputType, gui)
123 local tweensForButtonHoldBegin = {}
124 local tweensForButtonHoldEnd = {}
125 local tweensForFadeOut = {}
126 local tweensForFadeIn = {}
127 local tweenInfoInFullDuration = TweenInfo.new(
128 prompt.HoldDuration,
129 Enum.EasingStyle.Linear,
130 Enum.EasingDirection.Out
131 )
132 local tweenInfoOutHalfSecond = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
133 local tweenInfoFast = TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
134 local tweenInfoQuick = TweenInfo.new(0.06, Enum.EasingStyle.Linear, Enum.EasingDirection.Out)
135
136 local promptUI = Instance.new("BillboardGui")
137 promptUI.Name = "Prompt"
138 promptUI.AlwaysOnTop = true
139
140 local frame = Instance.new("Frame")
141 frame.Size = UDim2.fromScale(0.5, 1)
142 frame.BackgroundTransparency = 1
143 frame.BackgroundColor3 = Color3.new(0.07, 0.07, 0.07)
144 frame.Parent = promptUI
145
146 local roundedCorner = Instance.new("UICorner")
147 roundedCorner.Parent = frame
148
149 local inputFrame = Instance.new("Frame")
150 inputFrame.Name = "InputFrame"
151 inputFrame.Size = UDim2.fromScale(1, 1)
152 inputFrame.BackgroundTransparency = 1
153 inputFrame.SizeConstraint = Enum.SizeConstraint.RelativeYY
154 inputFrame.Parent = frame
155
156 local resizeableInputFrame = Instance.new("Frame")
157 resizeableInputFrame.Size = UDim2.fromScale(1, 1)
158 resizeableInputFrame.Position = UDim2.fromScale(0.5, 0.5)
159 resizeableInputFrame.AnchorPoint = Vector2.new(0.5, 0.5)
160 resizeableInputFrame.BackgroundTransparency = 1
161 resizeableInputFrame.Parent = inputFrame
162
163 local inputFrameScaler = Instance.new("UIScale")
164 inputFrameScaler.Parent = resizeableInputFrame
165
166 local inputFrameScaleFactor = inputType == Enum.ProximityPromptInputType.Touch and 1.6 or 1.33
167 table.insert(
168 tweensForButtonHoldBegin,
169 TweenService:Create(inputFrameScaler, tweenInfoFast, { Scale = inputFrameScaleFactor })
170 )
171 table.insert(tweensForButtonHoldEnd, TweenService:Create(inputFrameScaler, tweenInfoFast, { Scale = 1 }))
172
173 local actionText = Instance.new("TextLabel")
174 actionText.Name = "ActionText"
175 actionText.Size = UDim2.fromScale(1, 1)
176 actionText.Font = Enum.Font.GothamSemibold
177 actionText.TextSize = 19
178 actionText.BackgroundTransparency = 1
179 actionText.TextTransparency = 1
180 actionText.TextColor3 = Color3.new(1, 1, 1)
181 actionText.TextXAlignment = Enum.TextXAlignment.Left
182 actionText.Parent = frame
183 table.insert(tweensForButtonHoldBegin, TweenService:Create(actionText, tweenInfoFast, { TextTransparency = 1 }))
184 table.insert(tweensForButtonHoldEnd, TweenService:Create(actionText, tweenInfoFast, { TextTransparency = 0 }))
185 table.insert(tweensForFadeOut, TweenService:Create(actionText, tweenInfoFast, { TextTransparency = 1 }))
186 table.insert(tweensForFadeIn, TweenService:Create(actionText, tweenInfoFast, { TextTransparency = 0 }))
187
188 local objectText = Instance.new("TextLabel")
189 objectText.Name = "ObjectText"
190 objectText.Size = UDim2.fromScale(1, 1)
191 objectText.Font = Enum.Font.GothamSemibold
192 objectText.TextSize = 14
193 objectText.BackgroundTransparency = 1
194 objectText.TextTransparency = 1
195 objectText.TextColor3 = Color3.new(0.7, 0.7, 0.7)
196 objectText.TextXAlignment = Enum.TextXAlignment.Left
197 objectText.Parent = frame
198
199 table.insert(tweensForButtonHoldBegin, TweenService:Create(objectText, tweenInfoFast, { TextTransparency = 1 }))
200 table.insert(tweensForButtonHoldEnd, TweenService:Create(objectText, tweenInfoFast, { TextTransparency = 0 }))
201 table.insert(tweensForFadeOut, TweenService:Create(objectText, tweenInfoFast, { TextTransparency = 1 }))
202 table.insert(tweensForFadeIn, TweenService:Create(objectText, tweenInfoFast, { TextTransparency = 0 }))
203
204 table.insert(
205 tweensForButtonHoldBegin,
206 TweenService:Create(frame, tweenInfoFast, { Size = UDim2.fromScale(0.5, 1), BackgroundTransparency = 1 })
207 )
208 table.insert(
209 tweensForButtonHoldEnd,
210 TweenService:Create(frame, tweenInfoFast, { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 0.2 })
211 )
212 table.insert(
213 tweensForFadeOut,
214 TweenService:Create(frame, tweenInfoFast, { Size = UDim2.fromScale(0.5, 1), BackgroundTransparency = 1 })
215 )
216 table.insert(
217 tweensForFadeIn,
218 TweenService:Create(frame, tweenInfoFast, { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 0.2 })
219 )
220
221 local roundFrame = Instance.new("Frame")
222 roundFrame.Name = "RoundFrame"
223 roundFrame.Size = UDim2.fromOffset(48, 48)
224
225 roundFrame.AnchorPoint = Vector2.new(0.5, 0.5)
226 roundFrame.Position = UDim2.fromScale(0.5, 0.5)
227 roundFrame.BackgroundTransparency = 1
228 roundFrame.Parent = resizeableInputFrame
229
230 local roundedFrameCorner = Instance.new("UICorner")
231 roundedFrameCorner.CornerRadius = UDim.new(0.5, 0)
232 roundedFrameCorner.Parent = roundFrame
233
234 table.insert(tweensForFadeOut, TweenService:Create(roundFrame, tweenInfoQuick, { BackgroundTransparency = 1 }))
235 table.insert(tweensForFadeIn, TweenService:Create(roundFrame, tweenInfoQuick, { BackgroundTransparency = 0.5 }))
236
237 if inputType == Enum.ProximityPromptInputType.Gamepad then
238 if GamepadButtonImage[prompt.GamepadKeyCode] then
239 local icon = Instance.new("ImageLabel")
240 icon.Name = "ButtonImage"
241 icon.AnchorPoint = Vector2.new(0.5, 0.5)
242 icon.Size = UDim2.fromOffset(24, 24)
243 icon.Position = UDim2.fromScale(0.5, 0.5)
244 icon.BackgroundTransparency = 1
245 icon.ImageTransparency = 1
246 icon.Image = GamepadButtonImage[prompt.GamepadKeyCode]
247 icon.Parent = resizeableInputFrame
248 table.insert(tweensForFadeOut, TweenService:Create(icon, tweenInfoQuick, { ImageTransparency = 1 }))
249 table.insert(tweensForFadeIn, TweenService:Create(icon, tweenInfoQuick, { ImageTransparency = 0 }))
250 end
251 elseif inputType == Enum.ProximityPromptInputType.Touch then
252 local buttonImage = Instance.new("ImageLabel")
253 buttonImage.Name = "ButtonImage"
254 buttonImage.BackgroundTransparency = 1
255 buttonImage.ImageTransparency = 1
256 buttonImage.Size = UDim2.fromOffset(25, 31)
257 buttonImage.AnchorPoint = Vector2.new(0.5, 0.5)
258 buttonImage.Position = UDim2.fromScale(0.5, 0.5)
259 buttonImage.Image = "rbxasset://textures/ui/Controls/TouchTapIcon.png"
260 buttonImage.Parent = resizeableInputFrame
261
262 table.insert(tweensForFadeOut, TweenService:Create(buttonImage, tweenInfoQuick, { ImageTransparency = 1 }))
263 table.insert(tweensForFadeIn, TweenService:Create(buttonImage, tweenInfoQuick, { ImageTransparency = 0 }))
264 else
265 local buttonImage = Instance.new("ImageLabel")
266 buttonImage.Name = "ButtonImage"
267 buttonImage.BackgroundTransparency = 1
268 buttonImage.ImageTransparency = 1
269 buttonImage.Size = UDim2.fromOffset(28, 30)
270 buttonImage.AnchorPoint = Vector2.new(0.5, 0.5)
271 buttonImage.Position = UDim2.fromScale(0.5, 0.5)
272 buttonImage.Image = "rbxasset://textures/ui/Controls/key_single.png"
273 buttonImage.Parent = resizeableInputFrame
274 table.insert(tweensForFadeOut, TweenService:Create(buttonImage, tweenInfoQuick, { ImageTransparency = 1 }))
275 table.insert(tweensForFadeIn, TweenService:Create(buttonImage, tweenInfoQuick, { ImageTransparency = 0 }))
276
277 local buttonTextString = UserInputService:GetStringForKeyCode(prompt.KeyboardKeyCode)
278
279 local buttonTextImage = KeyboardButtonImage[prompt.KeyboardKeyCode]
280 if buttonTextImage == nil then
281 buttonTextImage = KeyboardButtonIconMapping[buttonTextString]
282 end
283
284 if buttonTextImage == nil then
285 local keyCodeMappedText = KeyCodeToTextMapping[prompt.KeyboardKeyCode]
286 if keyCodeMappedText then
287 buttonTextString = keyCodeMappedText
288 end
289 end
290
291 if buttonTextImage then
292 local icon = Instance.new("ImageLabel")
293 icon.Name = "ButtonImage"
294 icon.AnchorPoint = Vector2.new(0.5, 0.5)
295 icon.Size = UDim2.fromOffset(36, 36)
296 icon.Position = UDim2.fromScale(0.5, 0.5)
297 icon.BackgroundTransparency = 1
298 icon.ImageTransparency = 1
299 icon.Image = buttonTextImage
300 icon.Parent = resizeableInputFrame
301 table.insert(tweensForFadeOut, TweenService:Create(icon, tweenInfoQuick, { ImageTransparency = 1 }))
302 table.insert(tweensForFadeIn, TweenService:Create(icon, tweenInfoQuick, { ImageTransparency = 0 }))
303 elseif buttonTextString ~= nil and buttonTextString ~= "" then
304 local buttonText = Instance.new("TextLabel")
305 buttonText.Name = "ButtonText"
306 buttonText.Position = UDim2.fromOffset(0, -1)
307 buttonText.Size = UDim2.fromScale(1, 1)
308 buttonText.Font = Enum.Font.GothamSemibold
309 buttonText.TextSize = 14
310 if string.len(buttonTextString) > 2 then
311 buttonText.TextSize = 12
312 end
313 buttonText.BackgroundTransparency = 1
314 buttonText.TextTransparency = 1
315 buttonText.TextColor3 = Color3.new(1, 1, 1)
316 buttonText.TextXAlignment = Enum.TextXAlignment.Center
317 buttonText.Text = buttonTextString
318 buttonText.Parent = resizeableInputFrame
319 table.insert(tweensForFadeOut, TweenService:Create(buttonText, tweenInfoQuick, { TextTransparency = 1 }))
320 table.insert(tweensForFadeIn, TweenService:Create(buttonText, tweenInfoQuick, { TextTransparency = 0 }))
321 else
322 error(
323 "ProximityPrompt '"
324 .. prompt.Name
325 .. "' has an unsupported keycode for rendering UI: "
326 .. tostring(prompt.KeyboardKeyCode)
327 )
328 end
329 end
330
331 if inputType == Enum.ProximityPromptInputType.Touch or prompt.ClickablePrompt then
332 local button = Instance.new("TextButton")
333 button.BackgroundTransparency = 1
334 button.TextTransparency = 1
335 button.Size = UDim2.fromScale(1, 1)
336 button.Parent = promptUI
337
338 local buttonDown = false
339
340 button.InputBegan:Connect(function(input)
341 if
342 (
343 input.UserInputType == Enum.UserInputType.Touch
344 or input.UserInputType == Enum.UserInputType.MouseButton1
345 ) and input.UserInputState ~= Enum.UserInputState.Change
346 then
347 prompt:InputHoldBegin()
348 buttonDown = true
349 end
350 end)
351 button.InputEnded:Connect(function(input)
352 if
353 input.UserInputType == Enum.UserInputType.Touch
354 or input.UserInputType == Enum.UserInputType.MouseButton1
355 then
356 if buttonDown then
357 buttonDown = false
358 prompt:InputHoldEnd()
359 end
360 end
361 end)
362
363 promptUI.Active = true
364 end
365
366 if prompt.HoldDuration > 0 then
367 local circleBar = createCircularProgressBar()
368 circleBar.Parent = resizeableInputFrame
369 table.insert(
370 tweensForButtonHoldBegin,
371 TweenService:Create(circleBar.Progress, tweenInfoInFullDuration, { Value = 1 })
372 )
373 table.insert(
374 tweensForButtonHoldEnd,
375 TweenService:Create(circleBar.Progress, tweenInfoOutHalfSecond, { Value = 0 })
376 )
377 end
378
379 local holdBeganConnection
380 local holdEndedConnection
381 local triggeredConnection
382 local triggerEndedConnection
383
384 if prompt.HoldDuration > 0 then
385 holdBeganConnection = prompt.PromptButtonHoldBegan:Connect(function()
386 for _, tween in ipairs(tweensForButtonHoldBegin) do
387 tween:Play()
388 end
389 end)
390
391 holdEndedConnection = prompt.PromptButtonHoldEnded:Connect(function()
392 for _, tween in ipairs(tweensForButtonHoldEnd) do
393 tween:Play()
394 end
395 end)
396 end
397
398 triggeredConnection = prompt.Triggered:Connect(function()
399 for _, tween in ipairs(tweensForFadeOut) do
400 tween:Play()
401 end
402 end)
403
404 triggerEndedConnection = prompt.TriggerEnded:Connect(function()
405 for _, tween in ipairs(tweensForFadeIn) do
406 tween:Play()
407 end
408 end)
409
410 local function updateUIFromPrompt()
411 -- todo: Use AutomaticSize instead of GetTextSize when that feature becomes available
412 local actionTextSize = TextService:GetTextSize(
413 prompt.ActionText,
414 19,
415 Enum.Font.GothamSemibold,
416 Vector2.new(1000, 1000)
417 )
418 local objectTextSize = TextService:GetTextSize(
419 prompt.ObjectText,
420 14,
421 Enum.Font.GothamSemibold,
422 Vector2.new(1000, 1000)
423 )
424 local maxTextWidth = math.max(actionTextSize.X, objectTextSize.X)
425 local promptHeight = 72
426 local promptWidth = 72
427 local textPaddingLeft = 72
428
429 if
430 (prompt.ActionText ~= nil and prompt.ActionText ~= "")
431 or (prompt.ObjectText ~= nil and prompt.ObjectText ~= "")
432 then
433 promptWidth = maxTextWidth + textPaddingLeft + 24
434 end
435
436 local actionTextYOffset = 0
437 if prompt.ObjectText ~= nil and prompt.ObjectText ~= "" then
438 actionTextYOffset = 9
439 end
440 actionText.Position = UDim2.new(0.5, textPaddingLeft - promptWidth / 2, 0, actionTextYOffset)
441 objectText.Position = UDim2.new(0.5, textPaddingLeft - promptWidth / 2, 0, -10)
442
443 actionText.Text = prompt.ActionText
444 objectText.Text = prompt.ObjectText
445 actionText.AutoLocalize = prompt.AutoLocalize
446 actionText.RootLocalizationTable = prompt.RootLocalizationTable
447
448 objectText.AutoLocalize = prompt.AutoLocalize
449 objectText.RootLocalizationTable = prompt.RootLocalizationTable
450
451 promptUI.Size = UDim2.fromOffset(promptWidth, promptHeight)
452 promptUI.SizeOffset = Vector2.new(
453 prompt.UIOffset.X / promptUI.Size.Width.Offset,
454 prompt.UIOffset.Y / promptUI.Size.Height.Offset
455 )
456 end
457
458 local changedConnection = prompt.Changed:Connect(updateUIFromPrompt)
459 updateUIFromPrompt()
460
461 promptUI.Adornee = prompt.Parent
462 promptUI.Parent = gui
463
464 for _, tween in ipairs(tweensForFadeIn) do
465 tween:Play()
466 end
467
468 local function cleanup()
469 if holdBeganConnection then
470 holdBeganConnection:Disconnect()
471 end
472
473 if holdEndedConnection then
474 holdEndedConnection:Disconnect()
475 end
476
477 triggeredConnection:Disconnect()
478 triggerEndedConnection:Disconnect()
479 changedConnection:Disconnect()
480
481 for _, tween in ipairs(tweensForFadeOut) do
482 tween:Play()
483 end
484
485 task.wait(0.2)
486
487 promptUI.Parent = nil
488 end
489
490 return cleanup
491end
492
493local function onLoad()
494 ProximityPromptService.PromptShown:Connect(function(prompt, inputType)
495 if prompt.Style == Enum.ProximityPromptStyle.Default then
496 return
497 end
498
499 local gui = getScreenGui()
500
501 local cleanupFunction = createPrompt(prompt, inputType, gui)
502
503 prompt.PromptHidden:Wait()
504
505 cleanupFunction()
506 end)
507end
508
509onLoad()

Items

NameValueSummary
Default0
Custom1

Code Samples

Generating a Custom Proximity Prompt

1local UserInputService = game:GetService("UserInputService")
2local ProximityPromptService = game:GetService("ProximityPromptService")
3local TweenService = game:GetService("TweenService")
4local TextService = game:GetService("TextService")
5local Players = game:GetService("Players")
6
7local LocalPlayer = Players.LocalPlayer
8
9local PlayerGui = LocalPlayer:WaitForChild("PlayerGui")
10
11local GamepadButtonImage = {
12 [Enum.KeyCode.ButtonX] = "rbxasset://textures/ui/Controls/xboxX.png",
13 [Enum.KeyCode.ButtonY] = "rbxasset://textures/ui/Controls/xboxY.png",
14 [Enum.KeyCode.ButtonA] = "rbxasset://textures/ui/Controls/xboxA.png",
15 [Enum.KeyCode.ButtonB] = "rbxasset://textures/ui/Controls/xboxB.png",
16 [Enum.KeyCode.DPadLeft] = "rbxasset://textures/ui/Controls/dpadLeft.png",
17 [Enum.KeyCode.DPadRight] = "rbxasset://textures/ui/Controls/dpadRight.png",
18 [Enum.KeyCode.DPadUp] = "rbxasset://textures/ui/Controls/dpadUp.png",
19 [Enum.KeyCode.DPadDown] = "rbxasset://textures/ui/Controls/dpadDown.png",
20 [Enum.KeyCode.ButtonSelect] = "rbxasset://textures/ui/Controls/xboxmenu.png",
21 [Enum.KeyCode.ButtonL1] = "rbxasset://textures/ui/Controls/xboxLS.png",
22 [Enum.KeyCode.ButtonR1] = "rbxasset://textures/ui/Controls/xboxRS.png",
23}
24
25local KeyboardButtonImage = {
26 [Enum.KeyCode.Backspace] = "rbxasset://textures/ui/Controls/backspace.png",
27 [Enum.KeyCode.Return] = "rbxasset://textures/ui/Controls/return.png",
28 [Enum.KeyCode.LeftShift] = "rbxasset://textures/ui/Controls/shift.png",
29 [Enum.KeyCode.RightShift] = "rbxasset://textures/ui/Controls/shift.png",
30 [Enum.KeyCode.Tab] = "rbxasset://textures/ui/Controls/tab.png",
31}
32
33local KeyboardButtonIconMapping = {
34 ["'"] = "rbxasset://textures/ui/Controls/apostrophe.png",
35 [","] = "rbxasset://textures/ui/Controls/comma.png",
36 ["`"] = "rbxasset://textures/ui/Controls/graveaccent.png",
37 ["."] = "rbxasset://textures/ui/Controls/period.png",
38 [" "] = "rbxasset://textures/ui/Controls/spacebar.png",
39}
40
41local KeyCodeToTextMapping = {
42 [Enum.KeyCode.LeftControl] = "Ctrl",
43 [Enum.KeyCode.RightControl] = "Ctrl",
44 [Enum.KeyCode.LeftAlt] = "Alt",
45 [Enum.KeyCode.RightAlt] = "Alt",
46 [Enum.KeyCode.F1] = "F1",
47 [Enum.KeyCode.F2] = "F2",
48 [Enum.KeyCode.F3] = "F3",
49 [Enum.KeyCode.F4] = "F4",
50 [Enum.KeyCode.F5] = "F5",
51 [Enum.KeyCode.F6] = "F6",
52 [Enum.KeyCode.F7] = "F7",
53 [Enum.KeyCode.F8] = "F8",
54 [Enum.KeyCode.F9] = "F9",
55 [Enum.KeyCode.F10] = "F10",
56 [Enum.KeyCode.F11] = "F11",
57 [Enum.KeyCode.F12] = "F12",
58}
59
60local function getScreenGui()
61 local screenGui = PlayerGui:FindFirstChild("ProximityPrompts")
62 if screenGui == nil then
63 screenGui = Instance.new("ScreenGui")
64 screenGui.Name = "ProximityPrompts"
65 screenGui.ResetOnSpawn = false
66 screenGui.Parent = PlayerGui
67 end
68 return screenGui
69end
70
71local function createProgressBarGradient(parent, leftSide)
72 local frame = Instance.new("Frame")
73 frame.Size = UDim2.fromScale(0.5, 1)
74 frame.Position = UDim2.fromScale(leftSide and 0 or 0.5, 0)
75 frame.BackgroundTransparency = 1
76 frame.ClipsDescendants = true
77 frame.Parent = parent
78
79 local image = Instance.new("ImageLabel")
80 image.BackgroundTransparency = 1
81 image.Size = UDim2.fromScale(2, 1)
82 image.Position = UDim2.fromScale(leftSide and 0 or -1, 0)
83 image.Image = "rbxasset://textures/ui/Controls/RadialFill.png"
84 image.Parent = frame
85
86 local gradient = Instance.new("UIGradient")
87 gradient.Transparency = NumberSequence.new({
88 NumberSequenceKeypoint.new(0, 0),
89 NumberSequenceKeypoint.new(0.4999, 0),
90 NumberSequenceKeypoint.new(0.5, 1),
91 NumberSequenceKeypoint.new(1, 1),
92 })
93 gradient.Rotation = leftSide and 180 or 0
94 gradient.Parent = image
95
96 return gradient
97end
98
99local function createCircularProgressBar()
100 local bar = Instance.new("Frame")
101 bar.Name = "CircularProgressBar"
102 bar.Size = UDim2.fromOffset(58, 58)
103 bar.AnchorPoint = Vector2.new(0.5, 0.5)
104 bar.Position = UDim2.fromScale(0.5, 0.5)
105 bar.BackgroundTransparency = 1
106
107 local gradient1 = createProgressBarGradient(bar, true)
108 local gradient2 = createProgressBarGradient(bar, false)
109
110 local progress = Instance.new("NumberValue")
111 progress.Name = "Progress"
112 progress.Parent = bar
113 progress.Changed:Connect(function(value)
114 local angle = math.clamp(value * 360, 0, 360)
115 gradient1.Rotation = math.clamp(angle, 180, 360)
116 gradient2.Rotation = math.clamp(angle, 0, 180)
117 end)
118
119 return bar
120end
121
122local function createPrompt(prompt, inputType, gui)
123 local tweensForButtonHoldBegin = {}
124 local tweensForButtonHoldEnd = {}
125 local tweensForFadeOut = {}
126 local tweensForFadeIn = {}
127 local tweenInfoInFullDuration = TweenInfo.new(
128 prompt.HoldDuration,
129 Enum.EasingStyle.Linear,
130 Enum.EasingDirection.Out
131 )
132 local tweenInfoOutHalfSecond = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
133 local tweenInfoFast = TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
134 local tweenInfoQuick = TweenInfo.new(0.06, Enum.EasingStyle.Linear, Enum.EasingDirection.Out)
135
136 local promptUI = Instance.new("BillboardGui")
137 promptUI.Name = "Prompt"
138 promptUI.AlwaysOnTop = true
139
140 local frame = Instance.new("Frame")
141 frame.Size = UDim2.fromScale(0.5, 1)
142 frame.BackgroundTransparency = 1
143 frame.BackgroundColor3 = Color3.new(0.07, 0.07, 0.07)
144 frame.Parent = promptUI
145
146 local roundedCorner = Instance.new("UICorner")
147 roundedCorner.Parent = frame
148
149 local inputFrame = Instance.new("Frame")
150 inputFrame.Name = "InputFrame"
151 inputFrame.Size = UDim2.fromScale(1, 1)
152 inputFrame.BackgroundTransparency = 1
153 inputFrame.SizeConstraint = Enum.SizeConstraint.RelativeYY
154 inputFrame.Parent = frame
155
156 local resizeableInputFrame = Instance.new("Frame")
157 resizeableInputFrame.Size = UDim2.fromScale(1, 1)
158 resizeableInputFrame.Position = UDim2.fromScale(0.5, 0.5)
159 resizeableInputFrame.AnchorPoint = Vector2.new(0.5, 0.5)
160 resizeableInputFrame.BackgroundTransparency = 1
161 resizeableInputFrame.Parent = inputFrame
162
163 local inputFrameScaler = Instance.new("UIScale")
164 inputFrameScaler.Parent = resizeableInputFrame
165
166 local inputFrameScaleFactor = inputType == Enum.ProximityPromptInputType.Touch and 1.6 or 1.33
167 table.insert(
168 tweensForButtonHoldBegin,
169 TweenService:Create(inputFrameScaler, tweenInfoFast, { Scale = inputFrameScaleFactor })
170 )
171 table.insert(tweensForButtonHoldEnd, TweenService:Create(inputFrameScaler, tweenInfoFast, { Scale = 1 }))
172
173 local actionText = Instance.new("TextLabel")
174 actionText.Name = "ActionText"
175 actionText.Size = UDim2.fromScale(1, 1)
176 actionText.Font = Enum.Font.GothamSemibold
177 actionText.TextSize = 19
178 actionText.BackgroundTransparency = 1
179 actionText.TextTransparency = 1
180 actionText.TextColor3 = Color3.new(1, 1, 1)
181 actionText.TextXAlignment = Enum.TextXAlignment.Left
182 actionText.Parent = frame
183 table.insert(tweensForButtonHoldBegin, TweenService:Create(actionText, tweenInfoFast, { TextTransparency = 1 }))
184 table.insert(tweensForButtonHoldEnd, TweenService:Create(actionText, tweenInfoFast, { TextTransparency = 0 }))
185 table.insert(tweensForFadeOut, TweenService:Create(actionText, tweenInfoFast, { TextTransparency = 1 }))
186 table.insert(tweensForFadeIn, TweenService:Create(actionText, tweenInfoFast, { TextTransparency = 0 }))
187
188 local objectText = Instance.new("TextLabel")
189 objectText.Name = "ObjectText"
190 objectText.Size = UDim2.fromScale(1, 1)
191 objectText.Font = Enum.Font.GothamSemibold
192 objectText.TextSize = 14
193 objectText.BackgroundTransparency = 1
194 objectText.TextTransparency = 1
195 objectText.TextColor3 = Color3.new(0.7, 0.7, 0.7)
196 objectText.TextXAlignment = Enum.TextXAlignment.Left
197 objectText.Parent = frame
198
199 table.insert(tweensForButtonHoldBegin, TweenService:Create(objectText, tweenInfoFast, { TextTransparency = 1 }))
200 table.insert(tweensForButtonHoldEnd, TweenService:Create(objectText, tweenInfoFast, { TextTransparency = 0 }))
201 table.insert(tweensForFadeOut, TweenService:Create(objectText, tweenInfoFast, { TextTransparency = 1 }))
202 table.insert(tweensForFadeIn, TweenService:Create(objectText, tweenInfoFast, { TextTransparency = 0 }))
203
204 table.insert(
205 tweensForButtonHoldBegin,
206 TweenService:Create(frame, tweenInfoFast, { Size = UDim2.fromScale(0.5, 1), BackgroundTransparency = 1 })
207 )
208 table.insert(
209 tweensForButtonHoldEnd,
210 TweenService:Create(frame, tweenInfoFast, { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 0.2 })
211 )
212 table.insert(
213 tweensForFadeOut,
214 TweenService:Create(frame, tweenInfoFast, { Size = UDim2.fromScale(0.5, 1), BackgroundTransparency = 1 })
215 )
216 table.insert(
217 tweensForFadeIn,
218 TweenService:Create(frame, tweenInfoFast, { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 0.2 })
219 )
220
221 local roundFrame = Instance.new("Frame")
222 roundFrame.Name = "RoundFrame"
223 roundFrame.Size = UDim2.fromOffset(48, 48)
224
225 roundFrame.AnchorPoint = Vector2.new(0.5, 0.5)
226 roundFrame.Position = UDim2.fromScale(0.5, 0.5)
227 roundFrame.BackgroundTransparency = 1
228 roundFrame.Parent = resizeableInputFrame
229
230 local roundedFrameCorner = Instance.new("UICorner")
231 roundedFrameCorner.CornerRadius = UDim.new(0.5, 0)
232 roundedFrameCorner.Parent = roundFrame
233
234 table.insert(tweensForFadeOut, TweenService:Create(roundFrame, tweenInfoQuick, { BackgroundTransparency = 1 }))
235 table.insert(tweensForFadeIn, TweenService:Create(roundFrame, tweenInfoQuick, { BackgroundTransparency = 0.5 }))
236
237 if inputType == Enum.ProximityPromptInputType.Gamepad then
238 if GamepadButtonImage[prompt.GamepadKeyCode] then
239 local icon = Instance.new("ImageLabel")
240 icon.Name = "ButtonImage"
241 icon.AnchorPoint = Vector2.new(0.5, 0.5)
242 icon.Size = UDim2.fromOffset(24, 24)
243 icon.Position = UDim2.fromScale(0.5, 0.5)
244 icon.BackgroundTransparency = 1
245 icon.ImageTransparency = 1
246 icon.Image = GamepadButtonImage[prompt.GamepadKeyCode]
247 icon.Parent = resizeableInputFrame
248 table.insert(tweensForFadeOut, TweenService:Create(icon, tweenInfoQuick, { ImageTransparency = 1 }))
249 table.insert(tweensForFadeIn, TweenService:Create(icon, tweenInfoQuick, { ImageTransparency = 0 }))
250 end
251 elseif inputType == Enum.ProximityPromptInputType.Touch then
252 local buttonImage = Instance.new("ImageLabel")
253 buttonImage.Name = "ButtonImage"
254 buttonImage.BackgroundTransparency = 1
255 buttonImage.ImageTransparency = 1
256 buttonImage.Size = UDim2.fromOffset(25, 31)
257 buttonImage.AnchorPoint = Vector2.new(0.5, 0.5)
258 buttonImage.Position = UDim2.fromScale(0.5, 0.5)
259 buttonImage.Image = "rbxasset://textures/ui/Controls/TouchTapIcon.png"
260 buttonImage.Parent = resizeableInputFrame
261
262 table.insert(tweensForFadeOut, TweenService:Create(buttonImage, tweenInfoQuick, { ImageTransparency = 1 }))
263 table.insert(tweensForFadeIn, TweenService:Create(buttonImage, tweenInfoQuick, { ImageTransparency = 0 }))
264 else
265 local buttonImage = Instance.new("ImageLabel")
266 buttonImage.Name = "ButtonImage"
267 buttonImage.BackgroundTransparency = 1
268 buttonImage.ImageTransparency = 1
269 buttonImage.Size = UDim2.fromOffset(28, 30)
270 buttonImage.AnchorPoint = Vector2.new(0.5, 0.5)
271 buttonImage.Position = UDim2.fromScale(0.5, 0.5)
272 buttonImage.Image = "rbxasset://textures/ui/Controls/key_single.png"
273 buttonImage.Parent = resizeableInputFrame
274 table.insert(tweensForFadeOut, TweenService:Create(buttonImage, tweenInfoQuick, { ImageTransparency = 1 }))
275 table.insert(tweensForFadeIn, TweenService:Create(buttonImage, tweenInfoQuick, { ImageTransparency = 0 }))
276
277 local buttonTextString = UserInputService:GetStringForKeyCode(prompt.KeyboardKeyCode)
278
279 local buttonTextImage = KeyboardButtonImage[prompt.KeyboardKeyCode]
280 if buttonTextImage == nil then
281 buttonTextImage = KeyboardButtonIconMapping[buttonTextString]
282 end
283
284 if buttonTextImage == nil then
285 local keyCodeMappedText = KeyCodeToTextMapping[prompt.KeyboardKeyCode]
286 if keyCodeMappedText then
287 buttonTextString = keyCodeMappedText
288 end
289 end
290
291 if buttonTextImage then
292 local icon = Instance.new("ImageLabel")
293 icon.Name = "ButtonImage"
294 icon.AnchorPoint = Vector2.new(0.5, 0.5)
295 icon.Size = UDim2.fromOffset(36, 36)
296 icon.Position = UDim2.fromScale(0.5, 0.5)
297 icon.BackgroundTransparency = 1
298 icon.ImageTransparency = 1
299 icon.Image = buttonTextImage
300 icon.Parent = resizeableInputFrame
301 table.insert(tweensForFadeOut, TweenService:Create(icon, tweenInfoQuick, { ImageTransparency = 1 }))
302 table.insert(tweensForFadeIn, TweenService:Create(icon, tweenInfoQuick, { ImageTransparency = 0 }))
303 elseif buttonTextString ~= nil and buttonTextString ~= "" then
304 local buttonText = Instance.new("TextLabel")
305 buttonText.Name = "ButtonText"
306 buttonText.Position = UDim2.fromOffset(0, -1)
307 buttonText.Size = UDim2.fromScale(1, 1)
308 buttonText.Font = Enum.Font.GothamSemibold
309 buttonText.TextSize = 14
310 if string.len(buttonTextString) > 2 then
311 buttonText.TextSize = 12
312 end
313 buttonText.BackgroundTransparency = 1
314 buttonText.TextTransparency = 1
315 buttonText.TextColor3 = Color3.new(1, 1, 1)
316 buttonText.TextXAlignment = Enum.TextXAlignment.Center
317 buttonText.Text = buttonTextString
318 buttonText.Parent = resizeableInputFrame
319 table.insert(tweensForFadeOut, TweenService:Create(buttonText, tweenInfoQuick, { TextTransparency = 1 }))
320 table.insert(tweensForFadeIn, TweenService:Create(buttonText, tweenInfoQuick, { TextTransparency = 0 }))
321 else
322 error(
323 "ProximityPrompt '"
324 .. prompt.Name
325 .. "' has an unsupported keycode for rendering UI: "
326 .. tostring(prompt.KeyboardKeyCode)
327 )
328 end
329 end
330
331 if inputType == Enum.ProximityPromptInputType.Touch or prompt.ClickablePrompt then
332 local button = Instance.new("TextButton")
333 button.BackgroundTransparency = 1
334 button.TextTransparency = 1
335 button.Size = UDim2.fromScale(1, 1)
336 button.Parent = promptUI
337
338 local buttonDown = false
339
340 button.InputBegan:Connect(function(input)
341 if
342 (
343 input.UserInputType == Enum.UserInputType.Touch
344 or input.UserInputType == Enum.UserInputType.MouseButton1
345 ) and input.UserInputState ~= Enum.UserInputState.Change
346 then
347 prompt:InputHoldBegin()
348 buttonDown = true
349 end
350 end)
351 button.InputEnded:Connect(function(input)
352 if
353 input.UserInputType == Enum.UserInputType.Touch
354 or input.UserInputType == Enum.UserInputType.MouseButton1
355 then
356 if buttonDown then
357 buttonDown = false
358 prompt:InputHoldEnd()
359 end
360 end
361 end)
362
363 promptUI.Active = true
364 end
365
366 if prompt.HoldDuration > 0 then
367 local circleBar = createCircularProgressBar()
368 circleBar.Parent = resizeableInputFrame
369 table.insert(
370 tweensForButtonHoldBegin,
371 TweenService:Create(circleBar.Progress, tweenInfoInFullDuration, { Value = 1 })
372 )
373 table.insert(
374 tweensForButtonHoldEnd,
375 TweenService:Create(circleBar.Progress, tweenInfoOutHalfSecond, { Value = 0 })
376 )
377 end
378
379 local holdBeganConnection
380 local holdEndedConnection
381 local triggeredConnection
382 local triggerEndedConnection
383
384 if prompt.HoldDuration > 0 then
385 holdBeganConnection = prompt.PromptButtonHoldBegan:Connect(function()
386 for _, tween in ipairs(tweensForButtonHoldBegin) do
387 tween:Play()
388 end
389 end)
390
391 holdEndedConnection = prompt.PromptButtonHoldEnded:Connect(function()
392 for _, tween in ipairs(tweensForButtonHoldEnd) do
393 tween:Play()
394 end
395 end)
396 end
397
398 triggeredConnection = prompt.Triggered:Connect(function()
399 for _, tween in ipairs(tweensForFadeOut) do
400 tween:Play()
401 end
402 end)
403
404 triggerEndedConnection = prompt.TriggerEnded:Connect(function()
405 for _, tween in ipairs(tweensForFadeIn) do
406 tween:Play()
407 end
408 end)
409
410 local function updateUIFromPrompt()
411 -- todo: Use AutomaticSize instead of GetTextSize when that feature becomes available
412 local actionTextSize = TextService:GetTextSize(
413 prompt.ActionText,
414 19,
415 Enum.Font.GothamSemibold,
416 Vector2.new(1000, 1000)
417 )
418 local objectTextSize = TextService:GetTextSize(
419 prompt.ObjectText,
420 14,
421 Enum.Font.GothamSemibold,
422 Vector2.new(1000, 1000)
423 )
424 local maxTextWidth = math.max(actionTextSize.X, objectTextSize.X)
425 local promptHeight = 72
426 local promptWidth = 72
427 local textPaddingLeft = 72
428
429 if
430 (prompt.ActionText ~= nil and prompt.ActionText ~= "")
431 or (prompt.ObjectText ~= nil and prompt.ObjectText ~= "")
432 then
433 promptWidth = maxTextWidth + textPaddingLeft + 24
434 end
435
436 local actionTextYOffset = 0
437 if prompt.ObjectText ~= nil and prompt.ObjectText ~= "" then
438 actionTextYOffset = 9
439 end
440 actionText.Position = UDim2.new(0.5, textPaddingLeft - promptWidth / 2, 0, actionTextYOffset)
441 objectText.Position = UDim2.new(0.5, textPaddingLeft - promptWidth / 2, 0, -10)
442
443 actionText.Text = prompt.ActionText
444 objectText.Text = prompt.ObjectText
445 actionText.AutoLocalize = prompt.AutoLocalize
446 actionText.RootLocalizationTable = prompt.RootLocalizationTable
447
448 objectText.AutoLocalize = prompt.AutoLocalize
449 objectText.RootLocalizationTable = prompt.RootLocalizationTable
450
451 promptUI.Size = UDim2.fromOffset(promptWidth, promptHeight)
452 promptUI.SizeOffset = Vector2.new(
453 prompt.UIOffset.X / promptUI.Size.Width.Offset,
454 prompt.UIOffset.Y / promptUI.Size.Height.Offset
455 )
456 end
457
458 local changedConnection = prompt.Changed:Connect(updateUIFromPrompt)
459 updateUIFromPrompt()
460
461 promptUI.Adornee = prompt.Parent
462 promptUI.Parent = gui
463
464 for _, tween in ipairs(tweensForFadeIn) do
465 tween:Play()
466 end
467
468 local function cleanup()
469 if holdBeganConnection then
470 holdBeganConnection:Disconnect()
471 end
472
473 if holdEndedConnection then
474 holdEndedConnection:Disconnect()
475 end
476
477 triggeredConnection:Disconnect()
478 triggerEndedConnection:Disconnect()
479 changedConnection:Disconnect()
480
481 for _, tween in ipairs(tweensForFadeOut) do
482 tween:Play()
483 end
484
485 task.wait(0.2)
486
487 promptUI.Parent = nil
488 end
489
490 return cleanup
491end
492
493local function onLoad()
494 ProximityPromptService.PromptShown:Connect(function(prompt, inputType)
495 if prompt.Style == Enum.ProximityPromptStyle.Default then
496 return
497 end
498
499 local gui = getScreenGui()
500
501 local cleanupFunction = createPrompt(prompt, inputType, gui)
502
503 prompt.PromptHidden:Wait()
504
505 cleanupFunction()
506 end)
507end
508
509onLoad()