{"id":"biotoxin495/purchase-result-modal","name":"purchase-result-modal","scope":"biotoxin495","platform":"roblox","description":"Animated Roblox purchase result modal","version":"1.0.0","latest":"1.0.0","versions":["1.0.0"],"license":"MIT","licenseRating":"safe","licenseCaveats":[],"licenseVerified":true,"dependencies":{},"integrity":"653bbf3a0ce3b536f91a180653f6d71c5748b1784854ca87cd233c0ef824a84d","likes":0,"downloads":0,"install":"forest install biotoxin495/purchase-result-modal","url":"https://forest.dev/p/roblox/biotoxin495/purchase-result-modal","files":"https://api.forest.dev/ai/package/roblox/biotoxin495/purchase-result-modal/files","readme":"# PurchaseResultModal — Animated purchase result UI for Roblox\n\n**PurchaseResultModal** is a lightweight client-side Luau module for showing animated success or failure feedback after a purchase flow resolves.\n\nThe 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.\n\n## Quick example\n\n```lua\nlocal ReplicatedStorage = game:GetService(\"ReplicatedStorage\")\nlocal PurchaseResultModal = require(\n\tReplicatedStorage.Packages.PurchaseResultModal\n)\n\nlocal modal = PurchaseResultModal.new()\n\nif purchaseSucceeded then\n\tmodal:ShowSuccess()\nelse\n\tmodal:ShowFailure()\nend\n\n-- Reuse the modal for later results. Call modal:Destroy() when it is no longer needed.\n```\n\nWhen no `Parent` is supplied, the generated `ScreenGui` is placed in the local player's `PlayerGui`.\n\n## 🚀 Features\n\n- Show success and failure results with separate icons and color gradients\n- Animate the result card, status icon, and gradient shine\n- Automatically close after a configurable delay\n- Allow click or tap dismissal\n- Override the auto-close duration for each presentation\n- Replace an active result safely without stale timers closing the new one\n- Respect Roblox reduced-motion settings\n- No external runtime dependencies\n\n## 🛠️ Installation\n\n### ModuleScript\n\nPlace `init.luau` in a client-accessible ModuleScript, for example:\n\n```text\nReplicatedStorage\n└── Packages\n    └── PurchaseResultModal\n        └── init.luau\n```\n\nRequire and construct it from a `LocalScript`:\n\n```lua\nlocal ReplicatedStorage = game:GetService(\"ReplicatedStorage\")\nlocal PurchaseResultModal = require(\n\tReplicatedStorage:WaitForChild(\"Packages\"):WaitForChild(\"PurchaseResultModal\")\n)\n\nlocal modal = PurchaseResultModal.new()\n```\n\n### Wally\n\nAdd the package to your project's `wally.toml`:\n\n```toml\n[dependencies]\nPurchaseResultModal = \"biotoxin495/purchase-result-modal@1.0.0\"\n```\n\nConstruct the controller on the client.\n\n## Basic usage\n\nPass the result from your own purchase flow to the modal:\n\n```lua\nif purchaseSucceeded then\n\tmodal:ShowSuccess()\nelse\n\tmodal:ShowFailure()\nend\n```\n\nYou can choose the time a result stays open for one presentation:\n\n```lua\nmodal:ShowSuccess({\n\tAutoCloseDuration = 5,\n})\n```\n\nSet the duration to `0` to leave the result open until the player dismisses it or your code calls `Close()`:\n\n```lua\nmodal:ShowFailure({\n\tAutoCloseDuration = 0,\n})\n```\n\nThe 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.\n\n---\n\n# API reference\n\n## `PurchaseResultModal.new(config?) -> PurchaseResultModal`\n\nCreates 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.\n\n### Configuration\n\nAll fields are optional.\n\n| Option | Type | Default | Description |\n| --- | --- | --- | --- |\n| `Name` | `string` | `\"PurchaseResultModal\"` | Generated `ScreenGui` name. |\n| `Parent` | `Instance?` | Local `PlayerGui` | Parent of the generated UI. |\n| `DisplayOrder` | `number` | `110` | Generated `ScreenGui.DisplayOrder`. |\n| `AutoCloseDuration` | `number` | `3` | How long a result remains open. Use `0` to disable automatic closing. |\n| `AutoCloseStartDelay` | `number` | `0.3` | Delay before the auto-close timer starts. |\n| `DismissOnInput` | `boolean` | `true` | Enables click/tap dismissal. |\n| `RespectReducedMotion` | `boolean` | `true` | Reduces movement-heavy effects when reduced motion is enabled. |\n| `OpenDuration` | `number` | `0.35` | Card opening tween duration. |\n| `CloseDuration` | `number` | `0.35` | Card closing tween duration. |\n| `IconDuration` | `number` | `0.6` | Icon fade and rotation duration. |\n| `IconDelay` | `number` | `0.1` | Delay before the icon animation starts. |\n| `ShineDuration` | `number` | `1` | Duration of one gradient sweep. |\n| `ShinesPerCycle` | `number` | `2` | Consecutive sweeps in each shine cycle. |\n| `ShineInterval` | `number` | `2.5` | Pause between shine cycles. |\n| `ModalSize` | `UDim2` | `UDim2.new(0.25, 0, 0.4, 0)` | Result card size. |\n| `OpenPosition` | `UDim2` | Screen center | Result card position while open. |\n| `OpenAnchorPoint` | `Vector2` | `(0.5, 0.5)` | Result card anchor point while open. |\n| `ClosedPosition` | `UDim2` | `UDim2.new(0.5, 0, 0, -4)` | Result card position while closed. |\n| `ClosedAnchorPoint` | `Vector2` | `(0.5, 1)` | Result card anchor point while closed. |\n| `CornerRadius` | `UDim` | `UDim.new(0.06, 0)` | Card corner radius. |\n| `StrokeColor` | `Color3` | `Color3.fromRGB(27, 27, 27)` | Card outline color. |\n| `StrokeThickness` | `number` | `10` | Card outline thickness. |\n| `SuccessIcon` | `string` | `\"rbxassetid://106831201567242\"` | Success status icon. |\n| `FailureIcon` | `string` | `\"rbxassetid://116200809973713\"` | Failure status icon. |\n| `IconStartRotation` | `number` | `35` | Icon rotation at the start of its animation. |\n| `IconTargetRotation` | `number` | `0` | Icon rotation at the end of its animation. |\n| `SuccessGradient` | `ColorSequence` | Built-in success gradient | Gradient used for success results. |\n| `FailureGradient` | `ColorSequence` | Built-in failure gradient | Gradient used for failure results. |\n| `GradientRotation` | `number` | `15` | Rotation applied to the status gradients. |\n\nPer-presentation options currently support `AutoCloseDuration`:\n\n```lua\nmodal:Show(\"Success\", {\n\tAutoCloseDuration = 4,\n})\n```\n\n## `modal:Show(status, options?)`\n\nShows a result. `status` must be `\"Success\"` or `\"Failure\"`. Showing a new result replaces any currently active presentation.\n\n```lua\nmodal:Show(\"Success\")\nmodal:Show(\"Failure\", { AutoCloseDuration = 4 })\n```\n\n## `modal:ShowSuccess(options?)`\n\nConvenience method for `modal:Show(\"Success\", options)`.\n\n## `modal:ShowFailure(options?)`\n\nConvenience method for `modal:Show(\"Failure\", options)`.\n\n## `modal:Close(immediate?)`\n\nCloses the current result with the slide-up animation. Pass `true` to close immediately:\n\n```lua\nmodal:Close(true)\n```\n\n## `modal:IsOpen() -> boolean`\n\nReturns whether a result is currently active.\n\n## `modal:GetStatus() -> \"Success\" | \"Failure\" | nil`\n\nReturns the active result status, or `nil` when no result is open.\n\n## `modal:Destroy()`\n\nCancels owned tasks and tweens, disconnects input, destroys internal events, and removes the generated UI. A destroyed controller cannot be reused.\n\n## Signals\n\n```lua\nmodal.Opened:Connect(function(status)\n\tprint(\"Opened:\", status)\nend)\n\nmodal.Closed:Connect(function(status)\n\tprint(\"Closed:\", status)\nend)\n```\n\n`Opened` fires when a presentation begins. `Closed` fires when its closing transition finishes.\n\n## Replacement behavior\n\nEach 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:\n\n```lua\nmodal:ShowSuccess()\n\ntask.wait(0.5)\nmodal:ShowFailure()\n```\n\n## Notes\n\n- The default card is square, centered on screen, and includes an aspect-ratio constraint.\n- The success and failure gradients use separate built-in color sequences and share the same shine timing.\n- The invisible `DismissArea` captures click/tap input so dismissal does not fall through to underlying game UI.\n- The modal does not create a darkened backdrop. Use `PurchaseLoadingOverlay` separately if your design needs one.\n- Every generated Instance belongs to the controller. The same UI is reused for each presentation and removed by `Destroy()`.\n\n## Project structure\n\n```text\nPurchaseResultModal/\n├── init.luau\n├── README.md\n├── wally.toml\n├── sourcemap.json\n└── LICENSE\n```\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n\n---\n\nmade with ❤️ by biotoxin495\n","readmeTruncated":false}