Forest Logo
search
package_2

purchase-result-modal

By @biotoxin495

Roblox

Mirrored from Wally

PurchaseResultModal โ€” Animated purchase result UI for Roblox

PurchaseResultModal is a lightweight client-side Luau module for showing animated success or failure feedback after a purchase flow resolves.

The module creates a result card at runtime, animates its status icon and gradient, and closes it automatically or in response to player input. It presents the result your game provides; it does not determine whether a transaction succeeded.

Quick example

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local PurchaseResultModal = require(
	ReplicatedStorage.Packages.PurchaseResultModal
)

local modal = PurchaseResultModal.new()

if purchaseSucceeded then
	modal:ShowSuccess()
else
	modal:ShowFailure()
end

-- Reuse the modal for later results. Call modal:Destroy() when it is no longer needed.

When no Parent is supplied, the generated ScreenGui is placed in the local player's PlayerGui.

๐Ÿš€ Features

  • Show success and failure results with separate icons and color gradients
  • Animate the result card, status icon, and gradient shine
  • Automatically close after a configurable delay
  • Allow click or tap dismissal
  • Override the auto-close duration for each presentation
  • Replace an active result safely without stale timers closing the new one
  • Respect Roblox reduced-motion settings
  • No external runtime dependencies

๐Ÿ› ๏ธ Installation

ModuleScript

Place init.luau in a client-accessible ModuleScript, for example:

ReplicatedStorage
โ””โ”€โ”€ Packages
    โ””โ”€โ”€ PurchaseResultModal
        โ””โ”€โ”€ init.luau

Require and construct it from a LocalScript:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local PurchaseResultModal = require(
	ReplicatedStorage:WaitForChild("Packages"):WaitForChild("PurchaseResultModal")
)

local modal = PurchaseResultModal.new()

Wally

Add the package to your project's wally.toml:

[dependencies]
PurchaseResultModal = "biotoxin495/purchase-result-modal@1.0.0"

Construct the controller on the client.

Basic usage

Pass the result from your own purchase flow to the modal:

if purchaseSucceeded then
	modal:ShowSuccess()
else
	modal:ShowFailure()
end

You can choose the time a result stays open for one presentation:

modal:ShowSuccess({
	AutoCloseDuration = 5,
})

Set the duration to 0 to leave the result open until the player dismisses it or your code calls Close():

modal:ShowFailure({
	AutoCloseDuration = 0,
})

The package does not call MarketplaceService, listen to remotes, or decide whether a purchase succeeded. Do not show a failure result when a player merely cancels a purchase prompt unless that is the experience you want.


API reference

PurchaseResultModal.new(config?) -> PurchaseResultModal

Creates the controller and its generated ScreenGui. The UI is parented to config.Parent when provided, or to the local player's PlayerGui by default. Create the controller on the client.

Configuration

All fields are optional.

OptionTypeDefaultDescription
Namestring"PurchaseResultModal"Generated ScreenGui name.
ParentInstance?Local PlayerGuiParent of the generated UI.
DisplayOrdernumber110Generated ScreenGui.DisplayOrder.
AutoCloseDurationnumber3How long a result remains open. Use 0 to disable automatic closing.
AutoCloseStartDelaynumber0.3Delay before the auto-close timer starts.
DismissOnInputbooleantrueEnables click/tap dismissal.
RespectReducedMotionbooleantrueReduces movement-heavy effects when reduced motion is enabled.
OpenDurationnumber0.35Card opening tween duration.
CloseDurationnumber0.35Card closing tween duration.
IconDurationnumber0.6Icon fade and rotation duration.
IconDelaynumber0.1Delay before the icon animation starts.
ShineDurationnumber1Duration of one gradient sweep.
ShinesPerCyclenumber2Consecutive sweeps in each shine cycle.
ShineIntervalnumber2.5Pause between shine cycles.
ModalSizeUDim2UDim2.new(0.25, 0, 0.4, 0)Result card size.
OpenPositionUDim2Screen centerResult card position while open.
OpenAnchorPointVector2(0.5, 0.5)Result card anchor point while open.
ClosedPositionUDim2UDim2.new(0.5, 0, 0, -4)Result card position while closed.
ClosedAnchorPointVector2(0.5, 1)Result card anchor point while closed.
CornerRadiusUDimUDim.new(0.06, 0)Card corner radius.
StrokeColorColor3Color3.fromRGB(27, 27, 27)Card outline color.
StrokeThicknessnumber10Card outline thickness.
SuccessIconstring"rbxassetid://106831201567242"Success status icon.
FailureIconstring"rbxassetid://116200809973713"Failure status icon.
IconStartRotationnumber35Icon rotation at the start of its animation.
IconTargetRotationnumber0Icon rotation at the end of its animation.
SuccessGradientColorSequenceBuilt-in success gradientGradient used for success results.
FailureGradientColorSequenceBuilt-in failure gradientGradient used for failure results.
GradientRotationnumber15Rotation applied to the status gradients.

Per-presentation options currently support AutoCloseDuration:

modal:Show("Success", {
	AutoCloseDuration = 4,
})

modal:Show(status, options?)

Shows a result. status must be "Success" or "Failure". Showing a new result replaces any currently active presentation.

modal:Show("Success")
modal:Show("Failure", { AutoCloseDuration = 4 })

modal:ShowSuccess(options?)

Convenience method for modal:Show("Success", options).

modal:ShowFailure(options?)

Convenience method for modal:Show("Failure", options).

modal:Close(immediate?)

Closes the current result with the slide-up animation. Pass true to close immediately:

modal:Close(true)

modal:IsOpen() -> boolean

Returns whether a result is currently active.

modal:GetStatus() -> "Success" | "Failure" | nil

Returns the active result status, or nil when no result is open.

modal:Destroy()

Cancels owned tasks and tweens, disconnects input, destroys internal events, and removes the generated UI. A destroyed controller cannot be reused.

Signals

modal.Opened:Connect(function(status)
	print("Opened:", status)
end)

modal.Closed:Connect(function(status)
	print("Closed:", status)
end)

Opened fires when a presentation begins. Closed fires when its closing transition finishes.

Replacement behavior

Each presentation cancels the previous result's auto-close timer, icon and gradient tasks, closing task, and active tweens. An earlier result therefore cannot close a result shown afterward:

modal:ShowSuccess()

task.wait(0.5)
modal:ShowFailure()

Notes

  • The default card is square, centered on screen, and includes an aspect-ratio constraint.
  • The success and failure gradients use separate built-in color sequences and share the same shine timing.
  • The invisible DismissArea captures click/tap input so dismissal does not fall through to underlying game UI.
  • The modal does not create a darkened backdrop. Use PurchaseLoadingOverlay separately if your design needs one.
  • Every generated Instance belongs to the controller. The same UI is reused for each presentation and removed by Destroy().

Project structure

PurchaseResultModal/
โ”œโ”€โ”€ init.luau
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ wally.toml
โ”œโ”€โ”€ sourcemap.json
โ””โ”€โ”€ LICENSE

License

MIT โ€” see LICENSE.


made with โค๏ธ by biotoxin495

Package Details

Install command (Click to copy)


Version

1.0.0

License

MIT

check_circle

Safe for commercial use

Automated license review โ€” not legal advice.