Pulse.Draw
Pulse.Draw creates and manages visual overlays — highlights, drawing shapes, selection boxes. The API is simple by design: you describe what you want, Pulse creates the Roblox instance and manages its lifetime.
Highlights
A Highlight makes a model or part glow with a fill and outline colour.
Pulse.Draw.highlight(target, "MyKey", {
fill = Color3.fromRGB(255, 255, 0), -- fill colour
outline = Color3.fromRGB(255, 0, 0), -- outline colour
fillAlpha = 0.5, -- 0 = fully opaque, 1 = invisible
outlineAlpha = 0,
})
-- Remove it
Pulse.Draw.removeHighlight(target, "MyKey")
The key ("MyKey") identifies this highlight on this target. You can put multiple highlights on the same target using different keys. Calling highlight with the same key updates the existing one.
Important replication note: If you parent a Highlight to another player's character or a server-replicated model, Roblox will silently destroy it. For those cases, use Instance.new("Highlight") directly with Adornee set to the target and Parent set to CoreGui. See Roblox Gotchas for the full pattern.
Pulse.Draw.highlight is best used for models your client controls — things in workspace.Titans.Alive, your own character, etc.
FOV circles (screen drawing)
Draw a circle on screen — typically used for a targeting radius indicator.
local ring = Pulse.Draw.circle({
radius = 300,
color = Color3.fromRGB(255, 255, 255),
thickness = 2,
alpha = 0.8, -- 0 = solid, 1 = invisible
filled = false,
sides = 64,
visible = true,
})
Update each frame:
on.renderStepped({ when: enabled }, () => {
if (!ring) return
const cam = workspace.CurrentCamera
if (!cam) return
const sz = cam.ViewportSize
ring.Position = new Vector2(sz.X * 0.5, sz.Y * 0.5)
ring.Radius = radius()
ring.Visible = showCircle()
})
Destroy it:
Pulse.Draw.remove(ring)
ring = nil
Selection boxes
Outline a part or model with a SelectionBox:
Pulse.Draw.selectionBox(part, "HitboxESP", {
color = Color3.fromRGB(0, 255, 0),
thickness = 0.05,
})
-- Remove
Pulse.Draw.removeHighlight(part, "HitboxESP")
Selection boxes follow the part's bounding box, so they resize when the part changes size. Useful for visualising hitbox expansion.
Lifecycle and cleanup
Objects created with Pulse.Draw.circle must be destroyed with Pulse.Draw.remove — they're not tracked by the component lifecycle. Always pair creation with cleanup:
on.signal(enabled, (v) => {
if (v) {
circle = Pulse.Draw.circle({ ... })
} else {
Pulse.Draw.remove(circle)
circle = null
}
})
Highlights created with Pulse.Draw.highlight are tracked by key — calling removeHighlight(target, key) destroys them. If the component unmounts without removing them, they'll persist in the workspace. Always call removeHighlight in your on.signal(enabled, ...) cleanup branch.
Limitations
Pulse.Draw.highlightandselectionBoxdon't work correctly on replicated objects owned by other players. Use the CoreGui/Adornee pattern for those.- Circles are 2D screen-space drawing objects. They don't track a world position automatically — you update their position in a RenderStepped handler.
- There's no z-ordering API for circles. If you need ordering, use multiple layers with different drawing objects.