This customizable Minigame Task is 100% AI scripted.
No UI imports, no external assets – just pure code. I’m dropping the full prompt for FREE below! 👇
Want the full script too? > Since I can't upload it here, just reply with "DM" and I’ll send it over to you! 📜
"Create a Roblox "Hit the Target" minigame as a single LocalScript. Place it in StarterPlayer > StarterPlayerScripts. The entire GUI must be built purely via code with
Instance.new, no pre-made ScreenGui or assets required. Zero external dependencies. No server scripts needed. Fully standalone.
=== CONCEPT ===
A horizontal rhythm bar sits centered on screen inside a dark glassmorphism panel. A thin white indicator stripe bounces continuously left and right across the bar. Somewhere on the bar is a gray target zone. The player must click or tap exactly when the stripe overlaps the target zone. Each successful hit increases the stripe speed and shrinks the target zone, making it progressively harder. A miss penalizes the player by removing one point of progress and reverting the difficulty by one level. After the required number of successful hits (default 5), the minigame ends and fires a completion callback.
=== CONFIGURATION TABLE (top of script, all values tweakable) ===
BAR_WIDTH = 0.6 (bar takes 60 percent of screen width) BAR_HEIGHT = 0.08 (bar height is 8 percent of screen) GREEN_ZONE_WIDTH = 0.24 (starting target zone width as fraction of bar) GREEN_ZONE_SHRINK = 0.04 (target zone shrinks by this amount per successful hit) MIN_GREEN_ZONE_WIDTH = 0.08 (target zone never gets smaller than this) BASE_STRIPE_SPEED = 0.4 (stripe moves at 0.4 units per second initially) SPEED_INCREASE = 0.2 (speed increases by this per successful hit) REQUIRED_HITS = 5 (number of hits needed to complete the minigame)
=== COLOR PALETTE (define a COLORS table) ===
BACKGROUND: RGB(20, 20, 25) - dark panel background ACCENT: RGB(180, 180, 190) - muted gray accent for text ACCENT_DARK: RGB(100, 100, 110) - darker gray for borders and strokes BAR_BACKGROUND: RGB(30, 30, 35) - rhythm bar background GREEN_ZONE: RGB(140, 140, 150) - target zone color (gray, not green despite the name) STRIPE: RGB(220, 220, 230) - moving indicator stripe color TEXT: RGB(200, 200, 200) - general text color TITLE: RGB(180, 180, 190) - title text color SCORE_GOOD: RGB(150, 200, 150) - muted green for hit feedback SCORE_MISS: RGB(200, 100, 100) - muted red for miss feedback PROGRESS_BG: RGB(30, 30, 35) - progress bar background PROGRESS_FILL: RGB(160, 160, 170) - progress bar fill color
=== GUI STRUCTURE (all built with
Instance.new) ===
ScreenGui named "HitMinigameGUI", ResetOnSpawn false, starts Enabled false, parented to PlayerGui.
Overlay Frame: full screen (1,0,1,0), fully transparent (BackgroundTransparency 1), just a click-blocker layer.
MainFrame: centered panel, Size (0.6, 0, 0.6, 0), Position (0.2, 0, 0.2, 0), semi-transparent background (BackgroundTransparency 0.3), no border. Add UICorner with CornerRadius 16px. Add UIStroke with ACCENT_DARK color, thickness 3, transparency 0.3. Add UIGradient going top-to-bottom from RGB(40,45,50) to RGB(25,30,35), rotation 90.
Title TextLabel: inside MainFrame, top area, Size (1,0,0.14,0), Position (0,0,0.02,0), transparent background, font FredokaOne, TextScaled true, color TITLE. Add UIStroke for readability (ACCENT_DARK, thickness 1.5, transparency 0.5). Add UITextSizeConstraint min 28 max 56. Default text is "Task" but gets set dynamically via the API.
GameArea Frame: inside MainFrame, transparent container, Size (1,0,0.5,0), Position (0,0,0.22,0). Holds the rhythm bar and progress elements.
RhythmBar Frame: inside GameArea, Size (BAR_WIDTH, 0, BAR_HEIGHT, 0), centered with AnchorPoint (0.5, 0.5), Position (0.5, 0, 0.35, 0), color BAR_BACKGROUND, border 2px with RGB(60,60,70). Add UICorner with CornerRadius (0.3, 0).
GreenZone Frame (target zone): inside RhythmBar, Size (GREEN_ZONE_WIDTH, 0, 1, 0), Position (0.5, 0, 0, 0), AnchorPoint (0.5, 0), color GREEN_ZONE, no border. Add UICorner (0.3, 0).
MovingStripe Frame: inside RhythmBar, Size (0.04, 0, 1, 0), starts at Position (0, 0, 0, 0), color STRIPE, no border. Add UICorner (0.5, 0). Add a UIStroke glow effect with white color, thickness 2, transparency 0.5.
Progress TextLabel: inside GameArea, Size (0.4, 0, 0.15, 0), Position (0.3, 0, 0.62, 0), transparent background, font FredokaOne, TextScaled, color TEXT. Shows "0 / 5" format. UITextSizeConstraint min 28 max 48.
Progress Bar: inside GameArea, a background Frame (0.2, 0, 0.05, 0) at Position (0.4, 0, 0.82, 0), color PROGRESS_BG, fully rounded UICorner (0.5, 0). Inside it a fill Frame starting at Size (0, 0, 1, 0), color PROGRESS_FILL, same rounded corners. Fill animates via tween as progress increases.
Action TextLabel: inside MainFrame, bottom area, Size (1, 0, 0.12, 0), Position (0, 0, 0.85, 0), transparent background, font FredokaOne, TextScaled, color ACCENT. Text says "CLICK / TAP!". UITextSizeConstraint min 28 max 52.
Close Button (TextButton): inside MainFrame, top-right corner, Size (0, 40, 0, 40), Position (1, -10, 0, 10), AnchorPoint (1, 0), red background RGB(180, 60, 60), transparency 0.1, text "X", font GothamBold, TextSize 24, white text, ZIndex 10. Add UICorner 8px.
=== GAME STATE VARIABLES ===
isGameActive (boolean, false initially) successfulHits (number, starts at 0) stripePosition (number, 0 to 0.96 range, starts at 0 which is left edge) stripeDirection (1 for right, -1 for left, starts at 1) currentSpeed (starts at BASE_STRIPE_SPEED) currentGreenZoneWidth (starts at GREEN_ZONE_WIDTH, shrinks with hits) greenZonePosition (0 to 1 range, center of target zone, starts at 0.5) onGameComplete (callback function, nil initially) disabledPrompts (table storing ProximityPrompts that were disabled)
=== STRIPE MOVEMENT ===
Use RunService BindToRenderStep with a unique name like "HitMinigame_Update" and priority Camera 1. In the callback, receive deltaTime and update stripePosition by adding (stripeDirection times currentSpeed times deltaTime). When stripePosition goes below 0, clamp to 0 and flip direction to 1. When stripePosition goes above 0.96 (which is 1.0 minus the stripe width of 0.04), clamp to 0.96 and flip direction to -1. Update the stripe Frame Position to
UDim2.new(stripePosition, 0, 0, 0). This gives smooth frame-independent bouncing.
=== HIT DETECTION ===
When the player clicks, calculate stripeCenter as stripePosition 0.02 (half the stripe width). Calculate greenStart as greenZonePosition minus half of currentGreenZoneWidth. Calculate greenEnd as greenZonePosition plus half of currentGreenZoneWidth. If stripeCenter is between greenStart and greenEnd, it is a hit.
On HIT:
Increment successfulHits by 1
Show green "HIT!" feedback text
Flash the target zone bright green RGB(150, 255, 150) for 0.1 seconds then revert
Update progress display and progress bar
Increase currentSpeed by SPEED_INCREASE
If successfulHits reaches REQUIRED_HITS, wait 0.2 seconds then end the game with success
Otherwise, move the target zone to a new position (see below)
On MISS:
Show red "MISS!" feedback text
If successfulHits is greater than 0, subtract 1 from successfulHits
Revert currentSpeed by subtracting SPEED_INCREASE (clamp to BASE_STRIPE_SPEED minimum)
Revert currentGreenZoneWidth by adding GREEN_ZONE_SHRINK back (clamp to GREEN_ZONE_WIDTH maximum)
Update progress display
Animate the target zone size change with a tween
=== TARGET ZONE REPOSITIONING (after each hit) ===
Shrink currentGreenZoneWidth by GREEN_ZONE_SHRINK (clamp to MIN_GREEN_ZONE_WIDTH). Calculate valid position range ensuring the zone stays within the bar (minPos = half the zone width, maxPos = 1 minus half the zone width). Generate a random new position that is at least 0.2 away from the current position (use a repeat-until loop). Animate the zone to its new position AND new size simultaneously using TweenService with TweenInfo duration 0.3, EasingStyle Back, EasingDirection Out.
=== FEEDBACK ANIMATIONS ===
Create a temporary TextLabel at Position (0.5, 0, 0.45, 0) with AnchorPoint (0.5, 0.5), transparent background, GothamBold font, TextScaled, ZIndex 10. Add UITextSizeConstraint min 24 max 42. Use TweenService to animate TextTransparency to 1 and Position upward to (0.5, 0, 0.35, 0) over 0.6 seconds with Back easing Out. When the tween completes, destroy the label. This is non-blocking so gameplay continues during the animation.
=== INPUT HANDLING ===
Connect to UserInputService.InputBegan. Only process input when isGameActive is true. Skip if gameProcessed is true. Accept MouseButton1 and Touch input types, but ONLY if the input position falls within the MainFrame bounds (check using AbsolutePosition and AbsoluteSize of MainFrame). If input is within bounds, call the hit check function. If the player presses the Q key, force exit the minigame. Also connect the close button MouseButton1Click and TouchTap events to the force exit function.
=== GAME START FUNCTION ===
Accept parameters: callback function, optional requiredHits number, optional title string. If already active, return immediately. If requiredHits is provided, override REQUIRED_HITS. Reset all game state to initial values. Reset all UI elements (progress text, progress bar fill to 0, target zone position and size, stripe position to 0). Enable the ScreenGui. Disable ALL ProximityPrompts in workspace (iterate workspace GetDescendants, find all enabled ProximityPrompt instances, store them in the disabledPrompts table and set Enabled to false). Bind the render step for stripe movement.
=== GAME END FUNCTION ===
Accept a success boolean parameter. Calculate finalScore as 100 if success, 0 if not. Set isGameActive to false. Disable the ScreenGui. Unbind the render step. Re-enable all stored ProximityPrompts (check they still exist and have a parent before re-enabling). Clear the disabledPrompts table. Call the onGameComplete callback with the finalScore.
=== PUBLIC API ===
Create a HitMinigame table with three functions:
StartMiniGame(callback, requiredHits, title) - Sets the title label text if title is provided, then calls the internal start function. The callback receives a score number (100 for success, 0 for exit or fail).
IsActive() - Returns the isGameActive boolean.
ForceExit() - Ends the game with success false.
Store the table in _G.HitMinigame for global access from other scripts. Also return the table from the module.
=== USAGE EXAMPLE (for reference, not part of the script) ===
From any other LocalScript call: _G.HitMinigame.StartMiniGame(function(score) if score >= 100 then -- player completed it, give reward else -- player failed or exited end end, 5, "Pick the Lock")
"