Spotlight
Dims the screen and cuts a hole around a GuiObject.
You normally reach this through FocusUI, which drives it for you. Use it directly only when you want the highlight without a step around it.
const spotlight = TutorialKit.Spotlight.create({ DimTransparency = 0.5 })
spotlight:Focus(shopButton)
task.wait(3)
spotlight:Clear()
Why the panels live in a CanvasGroup
The obvious build for "dim everything except this rectangle" is four semi-transparent frames around a hole. Their alpha stacks wherever they touch, and that overlap renders as a visible seam along the edge of the hole. Padding cannot fix it, because the problem is overlap, not spacing.
A CanvasGroup flattens its descendants into a single image and applies GroupTransparency to
the result, so the panels can be fully opaque and overlap freely without ever double-darkening a
pixel.
The highlight stroke and the pointer stay outside that group on purpose: a UIStroke parented to
a CanvasGroup ignores GroupTransparency, so it would not fade with the rest.
Types
SpotlightConfig
interface SpotlightConfig {Name: string?--
ScreenGui name. Defaults to "TutorialSpotlight"
DisplayOrder: number?--
ScreenGui DisplayOrder. Defaults to 9700
DimTransparency: number?--
How much of the screen shows through. Defaults to 0.42
CornerRadius: number?--
Corner radius of the hole. Defaults to 8
StrokeThickness: number?--
Outline thickness. Defaults to 2.5
StrokeTransparency: number?--
Outline transparency. Defaults to 0.15
TweenTime: number?--
Seconds to slide between targets. Defaults to 0.6
Shine: boolean?--
Animated gradient on the outline. Defaults to true
ShineSpeed: number?--
Shine speed. Defaults to 0.35
PointerImage: string?--
Image for the bobbing pointer. No pointer without one
PointerGap: number?--
Gap between pointer and target. Defaults to 12
PointerBobDistance: number?--
How far the pointer bobs. Defaults to 8
PointerBobCycle: number?--
Seconds per bob. Defaults to 0.5
}
Styling for the overlay. Pass it as Spotlight in TutorialConfig to style a whole tutorial at
once:
Tutorial.build(steps, {
Spotlight = {
DimTransparency = 0.55,
StrokeColor = Color3.fromRGB(255, 214, 102),
PointerImage = "rbxassetid://1234567",
},
})
Functions
create
constructorCreates a standalone overlay with its own ScreenGui.
Tutorial.build already does this for you, so call it directly only when you want a highlight outside a tutorial. If you do, you own it: call Spotlight:Destroy yourself.
Errors
| Type | Description |
|---|---|
| "TutorialKit.Spotlight is client only" | Called from the server |
Focus
Spotlight:Focus() → ()Types
Moves the hole onto a target, tweening from wherever it was.
The overlay tracks the target every frame, so it follows a button that animates or a list that scrolls. Calling it again with a different target slides the hole across rather than cutting.
Clear
Spotlight:Clear() → ()Hides the overlay and stops tracking. Safe to call when nothing is focused.
IsVisible
Spotlight:IsVisible() → boolean--
Whether a target is currently focused
GetOverlay
The root frame, which is where you parent anything that must render above the dim.
const caption = Instance.new("TextLabel")
caption.Text = "Press here to open the shop"
caption.Parent = tutorial.Spotlight:GetOverlay()
Destroy
lifecycleSpotlight:Destroy() → ()Removes the ScreenGui and stops everything. Tutorial:Destroy already does this for you.