--!strict
-- Mobile-Only Notification UI with Material-Style Elevation
-- PC uses dynamic scaling (mobile unchanged)
local Players = game:GetService("Players")
local TweenService = game:GetService("TweenService")
local UserInputService = game:GetService("UserInputService")
local player = Players.LocalPlayer
local playerGui = player:WaitForChild("PlayerGui")
local IS_MOBILE = UserInputService.TouchEnabled
-- ScreenGui
local notificationUI = Instance.new("ScreenGui")
notificationUI.Name = "NotificationUI"
notificationUI.ResetOnSpawn = false
notificationUI.ScreenInsets = Enum.ScreenInsets.DeviceSafeInsets
notificationUI.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
notificationUI.Parent = playerGui
-- Notification template
local notificationFrame = Instance.new("Frame")
notificationFrame.Name = "NotificationFrame"
notificationFrame.Size = UDim2.new(0.88, 0, 0, 74)
notificationFrame.Position = UDim2.new(0.5, 0, 0.1, 0)
notificationFrame.AnchorPoint = Vector2.new(0.5, 0)
notificationFrame.BackgroundTransparency = 1
notificationFrame.BorderSizePixel = 0
notificationFrame.Visible = false
notificationFrame.Parent = notificationUI
-- 🔹 UIScale (PC only)
local uiScale = Instance.new("UIScale")
uiScale.Scale = 1
uiScale.Parent = notificationFrame
-- Surface gradient
local surfaceGradient = Instance.new("UIGradient")
surfaceGradient.Color = ColorSequence.new({
ColorSequenceKeypoint.new(0, Color3.fromRGB(48, 48, 54)),
ColorSequenceKeypoint.new(1, Color3.fromRGB(30, 30, 34))
})
surfaceGradient.Rotation = 90
surfaceGradient.Parent = notificationFrame
-- Rounded corners
local uiCorner = Instance.new("UICorner")
uiCorner.CornerRadius = UDim.new(0, 16)
uiCorner.Parent = notificationFrame
-- Ambient shadow
local ambientStroke = Instance.new("UIStroke")
ambientStroke.Color = Color3.fromRGB(0, 0, 0)
ambientStroke.Transparency = 0.9
ambientStroke.Thickness = 6
ambientStroke.ApplyStrokeMode = Enum.ApplyStrokeMode.Border
ambientStroke.Parent = notificationFrame
-- Key stroke
local keyStroke = Instance.new("UIStroke")
keyStroke.Color = Color3.fromRGB(255, 255, 255)
keyStroke.Transparency = 0.9
keyStroke.Thickness = 1.25
keyStroke.ApplyStrokeMode = Enum.ApplyStrokeMode.Border
keyStroke.Parent = notificationFrame
-- Padding
local uiPadding = Instance.new("UIPadding")
uiPadding.PaddingLeft = UDim.new(0, 18)
uiPadding.PaddingRight = UDim.new(0, 18)
uiPadding.PaddingTop = UDim.new(0, 14)
uiPadding.PaddingBottom = UDim.new(0, 14)
uiPadding.Parent = notificationFrame
-- Aspect ratio
local aspectRatio = Instance.new("UIAspectRatioConstraint")
aspectRatio.AspectRatio = 5.8
aspectRatio.AspectType = Enum.AspectType.FitWithinMaxSize
aspectRatio.Parent = notificationFrame
-- Label
local notificationLabel = Instance.new("TextLabel")
notificationLabel.Name = "NotificationLabel"
notificationLabel.Size = UDim2.new(1, 0, 1, 0)
notificationLabel.BackgroundTransparency = 1
notificationLabel.Text = ""
notificationLabel.Font = Enum.Font.GothamMedium
notificationLabel.TextSize = 17
notificationLabel.TextColor3 = Color3.fromRGB(245, 245, 247)
notificationLabel.TextTransparency = 1
notificationLabel.TextWrapped = true
notificationLabel.TextXAlignment = Enum.TextXAlignment.Left
notificationLabel.TextYAlignment = Enum.TextYAlignment.Center
notificationLabel.Parent = notificationFrame
-- Tween config
local tweenInfo = TweenInfo.new(
0.4,
Enum.EasingStyle.Quad,
Enum.EasingDirection.InOut
)
-- Positions
local ONSCREEN_POSITION = UDim2.new(0.5, 0, 0.1, 0)
local OFFSCREEN_POSITION = UDim2.new(0.5, 0, -0.25, 0)
-- 🔹 PC Dynamic Scaling
if not IS_MOBILE then
local camera = workspace.CurrentCamera
local function updateScale()
local viewportHeight = camera.ViewportSize.Y
-- Baseline: 900px tall screen ≈ scale 1
local scale = viewportHeight / 900
-- Clamp for sanity
scale = math.clamp(scale, 0.75, 1.25)
uiScale.Scale = scale
end
updateScale()
camera:GetPropertyChangedSignal("ViewportSize"):Connect(updateScale)
else
uiScale.Scale = 1 -- Mobile untouched
end
-- Show notification
local function showNotification(message: string, duration: number?)
local HoldDuration = duration or 4
local notificationInstance = notificationFrame:Clone()
notificationInstance.Visible = true
notificationInstance.Position = OFFSCREEN_POSITION
notificationInstance.BackgroundTransparency = 1
notificationInstance.Parent = notificationUI
local label = notificationInstance:FindFirstChild("NotificationLabel") :: TextLabel
label.Text = message
label.TextTransparency = 1
-- Slide + Fade In
local slideInTween = TweenService:Create(notificationInstance, tweenInfo, {
Position = ONSCREEN_POSITION,
BackgroundTransparency = 0
})
local textFadeInTween = TweenService:Create(label, tweenInfo, {
TextTransparency = 0
})
slideInTween:Play()
textFadeInTween:Play()
slideInTween.Completed:Wait()
-- Hold
task.wait(HoldDuration)
-- Slide + Fade Out
local slideOutTween = TweenService:Create(notificationInstance, tweenInfo, {
Position = OFFSCREEN_POSITION,
BackgroundTransparency = 1
})
local textFadeOutTween = TweenService:Create(label, tweenInfo, {
TextTransparency = 1
})
slideOutTween:Play()
textFadeOutTween:Play()
slideOutTween.Completed:Wait()
if notificationInstance.Parent then
notificationInstance:Destroy()
end
end
-- Example
task.wait(1)
showNotification("Dynamic scaling enabled for PC.", 3)
return {
Show = showNotification
}