@rbxts/gizmos 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Colin Miller
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # @rbxts/gizmos
2
+
3
+ Debug drawing library for Roblox with support for lines, rays, shapes, raycasts, and more.
4
+
5
+ ## Credits
6
+
7
+ Original Luau implementation by **sg3cko**
8
+ [DevForum Post](https://devforum.roblox.com/t/roblox-gizmos-for-debug-drawing-now-available/3294608)
9
+
10
+ TypeScript package by Colin Miller (SnarlyZoo)
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install @rbxts/gizmos
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```typescript
21
+ import Gizmos from "@rbxts/gizmos";
22
+
23
+ // Draw colored shapes
24
+ Gizmos.setColor("red");
25
+ Gizmos.drawLine(Vector3.zero, new Vector3(0, 10, 0));
26
+
27
+ Gizmos.setColor("blue");
28
+ Gizmos.drawSphere(new Vector3(5, 5, 5), 2);
29
+
30
+ // Visualize raycasts
31
+ const params = new RaycastParams();
32
+ const result = workspace.Raycast(origin, direction, params);
33
+ Gizmos.drawRaycast(origin, direction, result);
34
+
35
+ // Draw text in world space
36
+ Gizmos.drawText(new Vector3(0, 10, 0), "Player spawn point");
37
+
38
+ // Log to screen
39
+ Gizmos.log("Frame:", tick());
40
+ ```
41
+
42
+ ## Features
43
+
44
+ - **Shapes**: Lines, rays, paths, points, cubes, circles, spheres, pyramids
45
+ - **Raycasts**: Visualize raycasts, spherecasts, and blockcasts with hit detection
46
+ - **Text**: World-space and on-screen text rendering
47
+ - **Colors**: Built-in color presets (red, green, blue, yellow, cyan, magenta, orange, purple, white, gray, black)
48
+ - **Trailing paths**: Track object movement over time
49
+ - **Auto-clearing**: Automatically clears each frame (configurable)
50
+
51
+ ## API
52
+
53
+ ### Drawing
54
+
55
+ - `setColor(color: string | Color3)` - Set drawing color
56
+ - `setTransparency(value: number)` - Set transparency (0-1)
57
+ - `drawLine(from: Vector3, to: Vector3)` - Draw a line
58
+ - `drawRay(origin: Vector3, direction: Vector3)` - Draw a ray with arrow
59
+ - `drawPath(points: Vector3[], closed?: boolean, dotsSize?: number)` - Draw connected path
60
+ - `drawPoint(position: Vector3, size?: number)` - Draw point marker
61
+ - `drawCube(position: Vector3 | CFrame, size: Vector3)` - Draw wireframe cube
62
+ - `drawCircle(position: Vector3, radius: number, normal?: Vector3)` - Draw circle
63
+ - `drawSphere(position: Vector3 | CFrame, radius: number)` - Draw sphere
64
+ - `drawPyramid(position: Vector3 | CFrame, size: number, height: number)` - Draw pyramid
65
+ - `drawCFrame(cf: CFrame, size?: number, color?: Color3)` - Draw CFrame axes
66
+
67
+ ### Raycasts
68
+
69
+ - `drawRaycast(origin: Vector3, direction: Vector3, result?: RaycastResult)` - Visualize raycast
70
+ - `drawSpherecast(origin: Vector3, radius: number, direction: Vector3, result?: RaycastResult)` - Visualize spherecast
71
+ - `drawBlockcast(cf: CFrame, size: Vector3, direction: Vector3, result?: RaycastResult)` - Visualize blockcast
72
+
73
+ ### Text & Logging
74
+
75
+ - `drawText(position: Vector3, ...args: unknown[])` - Draw text at world position
76
+ - `log(...args: unknown[])` - Log to on-screen display
77
+
78
+ ### Utilities
79
+
80
+ - `addToPath(name: string, position: Vector3, dotsSize?: number)` - Add point to trailing path
81
+ - `forceUpdate()` - Manually clear and update gizmos
82
+ - `test()` - Run visual test of all features
83
+
84
+ ### Properties
85
+
86
+ - `clear: boolean` - Auto-clear each frame (default: true)
87
+
88
+ ## License
89
+
90
+ MIT
91
+
92
+ ## Links
93
+
94
+ - [Original DevForum Post](https://devforum.roblox.com/t/roblox-gizmos-for-debug-drawing-now-available/3294608)
95
+ - [GitHub Repository](https://github.com/cmmiller26/rbxts-gizmos)
package/out/index.d.ts ADDED
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Gizmos - Debug drawing library for Roblox
3
+ *
4
+ * Original Luau implementation by sg3cko
5
+ * https://devforum.roblox.com/t/roblox-gizmos-for-debug-drawing-now-available/3294608
6
+ *
7
+ * TypeScript package by Colin Miller (SnarlyZoo)
8
+ */
9
+
10
+ interface Gizmos {
11
+ /**
12
+ * Whether to automatically clear gizmos each frame
13
+ * @default true
14
+ */
15
+ clear: boolean;
16
+
17
+ /**
18
+ * Set the color for subsequent draw calls
19
+ * @param color Color name ('red', 'green', 'blue', 'yellow', 'cyan', 'magenta', 'orange', 'purple', 'white', 'gray', 'black') or Color3 value
20
+ */
21
+ setColor(color: string | Color3): void;
22
+
23
+ /**
24
+ * Set the transparency for subsequent draw calls
25
+ * @param value Transparency value from 0 (opaque) to 1 (fully transparent)
26
+ */
27
+ setTransparency(value: number): void;
28
+
29
+ /**
30
+ * Draw a line between two points
31
+ * @param from Start position
32
+ * @param to End position
33
+ */
34
+ drawLine(from: Vector3, to: Vector3): void;
35
+
36
+ /**
37
+ * Draw a ray with an arrow head
38
+ * @param origin Starting position of the ray
39
+ * @param direction Direction and length of the ray
40
+ */
41
+ drawRay(origin: Vector3, direction: Vector3): void;
42
+
43
+ /**
44
+ * Draw a path connecting multiple points
45
+ * @param points Array of Vector3 positions to connect
46
+ * @param closed Whether to connect the last point back to the first
47
+ * @param dotsSize Optional size of dots to draw at each point (0 = no dots)
48
+ */
49
+ drawPath(points: Vector3[], closed?: boolean, dotsSize?: number): void;
50
+
51
+ /**
52
+ * Draw a point marker at a position
53
+ * @param position Location to draw the point
54
+ * @param size Size of the point marker
55
+ */
56
+ drawPoint(position: Vector3, size?: number): void;
57
+
58
+ /**
59
+ * Draw a wireframe cube
60
+ * @param position Center position or CFrame of the cube
61
+ * @param size Size of the cube on each axis
62
+ */
63
+ drawCube(position: Vector3 | CFrame, size: Vector3): void;
64
+
65
+ /**
66
+ * Draw a wireframe circle
67
+ * @param position Center position of the circle
68
+ * @param radius Radius of the circle
69
+ * @param normal Normal vector defining the circle's plane (defaults to Vector3.yAxis)
70
+ */
71
+ drawCircle(position: Vector3, radius: number, normal?: Vector3): void;
72
+
73
+ /**
74
+ * Draw a wireframe sphere
75
+ * @param position Center position or CFrame of the sphere
76
+ * @param radius Radius of the sphere
77
+ */
78
+ drawSphere(position: Vector3 | CFrame, radius: number): void;
79
+
80
+ /**
81
+ * Draw a wireframe pyramid
82
+ * @param position Base center position or CFrame of the pyramid
83
+ * @param size Size of the pyramid's base
84
+ * @param height Height of the pyramid
85
+ */
86
+ drawPyramid(position: Vector3 | CFrame, size: number, height: number): void;
87
+
88
+ /**
89
+ * Draw a CFrame as colored axes (red = right, green = up, blue = -look)
90
+ * @param cf CFrame to visualize
91
+ * @param size Length of the axes
92
+ * @param color Optional single color for all axes (defaults to RGB for XYZ)
93
+ */
94
+ drawCFrame(cf: CFrame, size?: number, color?: Color3): void;
95
+
96
+ /**
97
+ * Draw text at a world position
98
+ * @param position World position to display the text
99
+ * @param args Values to display (strings, numbers, Vector3, CFrame are automatically formatted)
100
+ */
101
+ drawText(position: Vector3, ...args: unknown[]): void;
102
+
103
+ /**
104
+ * Log text to the on-screen debug display
105
+ * @param args Values to log (strings, numbers, Vector3, CFrame are automatically formatted)
106
+ */
107
+ log(...args: unknown[]): void;
108
+
109
+ /**
110
+ * Visualize a raycast with its result
111
+ * @param origin Starting position of the raycast
112
+ * @param direction Direction and maximum distance of the raycast
113
+ * @param result RaycastResult (green if hit, red if miss)
114
+ */
115
+ drawRaycast(origin: Vector3, direction: Vector3, result: RaycastResult | undefined): void;
116
+
117
+ /**
118
+ * Visualize a spherecast with its result
119
+ * @param origin Starting position of the spherecast
120
+ * @param radius Radius of the sphere
121
+ * @param direction Direction and maximum distance of the spherecast
122
+ * @param result RaycastResult (green if hit, red if miss)
123
+ */
124
+ drawSpherecast(origin: Vector3, radius: number, direction: Vector3, result: RaycastResult | undefined): void;
125
+
126
+ /**
127
+ * Visualize a blockcast (box-shaped raycast) with its result
128
+ * @param cf CFrame defining position and orientation of the block
129
+ * @param size Size of the block on each axis
130
+ * @param direction Direction and maximum distance of the blockcast
131
+ * @param result RaycastResult (green if hit, red if miss)
132
+ */
133
+ drawBlockcast(cf: CFrame, size: Vector3, direction: Vector3, result: RaycastResult | undefined): void;
134
+
135
+ /**
136
+ * Add a point to a named trailing path (useful for visualizing movement over time)
137
+ * @param name Unique identifier for this path
138
+ * @param position Position to add to the path
139
+ * @param dotsSize Optional size of dots to draw at each point (0 = no dots)
140
+ */
141
+ addToPath(name: string, position: Vector3, dotsSize?: number): void;
142
+
143
+ /**
144
+ * Manually force an update and clear of all gizmos
145
+ */
146
+ forceUpdate(): void;
147
+
148
+ /**
149
+ * Run a visual test showcasing all gizmo drawing functions
150
+ */
151
+ test(): void;
152
+ }
153
+
154
+ declare const Gizmos: Gizmos;
155
+ export = Gizmos;
package/out/init.lua ADDED
@@ -0,0 +1,486 @@
1
+ local Gizmos = {}
2
+
3
+ local wfh: WireframeHandleAdornment = nil
4
+ local label: TextLabel = nil
5
+ local commands = {}
6
+ local trailers = {}
7
+
8
+ local hitColor, missColor = 'green', 'red'
9
+
10
+ Gizmos.clear = true
11
+
12
+ local colors = {
13
+ red = Color3.new(1, 0, 0),
14
+ green = Color3.new(0, 1, 0),
15
+ blue = Color3.new(0, 0, 1),
16
+ yellow = Color3.new(1, 1, 0),
17
+ cyan = Color3.new(0, 1, 1),
18
+ magenta = Color3.new(1, 0, 1),
19
+ orange = Color3.new(1, 0.5, 0),
20
+ purple = Color3.new(0.5, 0, 1),
21
+ white = Color3.new(1, 1, 1),
22
+ gray = Color3.new(0.5, 0.5, 0.5),
23
+ black = Color3.new(0, 0, 0),
24
+ }
25
+
26
+ local function findOrMakeGizmos()
27
+ wfh = wfh or workspace:FindFirstChild('Gizmos')
28
+ if not wfh then
29
+ wfh = Instance.new('WireframeHandleAdornment')
30
+ wfh.Name = 'Gizmos'
31
+ wfh.Parent = workspace
32
+ assert(workspace.WorldPivot:FuzzyEq(CFrame.identity), 'workspace is expected to have identity CFrame')
33
+ wfh.Color3 = Color3.new(1, 1, 1)
34
+ wfh.Adornee = workspace
35
+ wfh.AlwaysOnTop = true
36
+ end
37
+ end
38
+
39
+ local function helper_getGui()
40
+ local localPlayer = game:GetService('Players').LocalPlayer
41
+ if localPlayer then
42
+ return localPlayer:WaitForChild('PlayerGui', 3)
43
+ else
44
+ return game:GetService('StarterGui')
45
+ end
46
+ end
47
+
48
+ local function findOrMakeLabel()
49
+ local gui = helper_getGui()
50
+ if not gui then return end
51
+ label = gui:FindFirstChild('TextLabelGizmos', true)
52
+ if not label then
53
+ local screengui = Instance.new('ScreenGui', gui)
54
+ screengui.Name = 'ScreenGuiGizmos'
55
+ label = Instance.new('TextLabel', screengui)
56
+ label.Name = 'TextLabelGizmos'
57
+ label.BackgroundTransparency = 1
58
+ label.Position = UDim2.new(0, 10, 1, -10)
59
+ label.AnchorPoint = Vector2.new(0,1)
60
+ label.TextXAlignment = Enum.TextXAlignment.Left
61
+ label.TextYAlignment = Enum.TextYAlignment.Bottom
62
+ label.FontFace = Font.fromEnum(Enum.Font.RobotoMono)
63
+ label.TextColor3 = Color3.new(1,1,1)
64
+ label.TextStrokeColor3 = Color3.new(0,0,0)
65
+ label.TextStrokeTransparency = 0.5
66
+ label.TextSize = 14
67
+ end
68
+ end
69
+
70
+ local Trailer = {}
71
+ Trailer.__index = Trailer
72
+
73
+ function Trailer.new(limit)
74
+ local defaultLimit = 300
75
+ local self = setmetatable({}, Trailer)
76
+ self.limit = limit or defaultLimit
77
+ self.values = {}
78
+ return self
79
+ end
80
+
81
+ function Trailer:addValue(value)
82
+ table.insert(self.values, value)
83
+ if #self.values > self.limit then
84
+ table.remove(self.values, 1)
85
+ end
86
+ end
87
+
88
+ function Trailer:getValues()
89
+ return self.values
90
+ end
91
+
92
+ local function setColor(color: string | Color3)
93
+ local color3 = if typeof(color) == 'string' then colors[color] else color
94
+ wfh.Color3 = color3
95
+ end
96
+
97
+ local function setTransparency(value: number)
98
+ wfh.Transparency = value
99
+ end
100
+
101
+ local function drawLine(from: Vector3, to: Vector3)
102
+ wfh:AddLine(from, to)
103
+ end
104
+
105
+ local function helper_getPerpendicularVector(v: Vector3): Vector3
106
+ local perp: Vector3 = Vector3.new(-v.y, v.x, 0)
107
+ if perp.Magnitude == 0 then
108
+ perp = Vector3.new(0, -v.z, v.y)
109
+ end
110
+ return perp.Unit
111
+ end
112
+
113
+ local function drawRay(origin: Vector3, direction: Vector3)
114
+ local endPoint = origin + direction
115
+ wfh:AddLine(origin, endPoint)
116
+
117
+ local arrowLength, arrowAngle = direction.Magnitude/20, math.rad(30)
118
+
119
+ local dir = direction.Unit
120
+ local perp = helper_getPerpendicularVector(dir)
121
+ local left = endPoint - dir * arrowLength + perp * arrowLength * math.tan(arrowAngle)
122
+ local right = endPoint - dir * arrowLength - perp * arrowLength * math.tan(arrowAngle)
123
+ wfh:AddLine(endPoint, left)
124
+ wfh:AddLine(endPoint, right)
125
+ end
126
+
127
+ local function drawPath(points: {Vector3}, closed: boolean?, dotsSize: number?)
128
+ closed = closed or false
129
+ dotsSize = dotsSize or 0
130
+ wfh:AddPath(points, closed)
131
+ if dotsSize > 0 then
132
+ for _, point in ipairs(points) do
133
+ drawCube(point, Vector3.one * dotsSize)
134
+ end
135
+ end
136
+ end
137
+
138
+ local function drawPoint(pos: Vector3, size: number?)
139
+ size = size or 0.1
140
+ wfh:AddLines({
141
+ pos - Vector3.xAxis * size, pos + Vector3.xAxis * size,
142
+ pos - Vector3.yAxis * size, pos + Vector3.yAxis * size,
143
+ pos - Vector3.zAxis * size, pos + Vector3.zAxis * size})
144
+ end
145
+
146
+ local function drawCube(pos: Vector3 | CFrame, size: Vector3)
147
+ local cf = if typeof(pos) == 'Vector3' then CFrame.new(pos) else pos
148
+ local halfSize = size * 0.5
149
+ local min = -halfSize
150
+ local max = halfSize
151
+ local v = {
152
+ cf * min,
153
+ cf * Vector3.new(max.x, min.y, min.z),
154
+ cf * Vector3.new(max.x, min.y, max.z),
155
+ cf * Vector3.new(min.x, min.y, max.z),
156
+ cf * Vector3.new(min.x, max.y, min.z),
157
+ cf * Vector3.new(max.x, max.y, min.z),
158
+ cf * max,
159
+ cf * Vector3.new(min.x, max.y, max.z),
160
+ }
161
+ wfh:AddLines({
162
+ v[1], v[2],
163
+ v[2], v[3],
164
+ v[3], v[4],
165
+ v[4], v[1],
166
+ v[5], v[6],
167
+ v[6], v[7],
168
+ v[7], v[8],
169
+ v[8], v[5],
170
+ v[1], v[5],
171
+ v[2], v[6],
172
+ v[3], v[7],
173
+ v[4], v[8],
174
+ })
175
+ end
176
+
177
+ local function drawCircle(pos: Vector3, radius: number, normal: Vector3?)
178
+ local segments = 16
179
+ normal = normal or Vector3.yAxis
180
+ local cf = CFrame.lookAlong(pos, normal)
181
+ local angle = 2 * math.pi / segments
182
+
183
+ local points = {}
184
+ for i = 1, segments do
185
+ local localpoint = Vector3.new(math.cos(i * angle), math.sin(i * angle), 0) * radius
186
+ local point = cf:PointToWorldSpace(localpoint)
187
+ table.insert(points, point)
188
+ end
189
+ wfh:AddPath(points, true)
190
+ end
191
+
192
+ local function drawSphere(pos: Vector3 | CFrame, radius: number)
193
+ local cf = if typeof(pos) == 'Vector3' then CFrame.new(pos) else pos
194
+ drawCircle(cf.Position, radius, cf.Rotation * Vector3.xAxis)
195
+ drawCircle(cf.Position, radius, cf.Rotation * Vector3.yAxis)
196
+ drawCircle(cf.Position, radius, cf.Rotation * Vector3.zAxis)
197
+ end
198
+
199
+ local function drawPyramid(pos: Vector3 | CFrame, size: number, height: number)
200
+ local cf = if typeof(pos) == 'Vector3' then CFrame.new(pos) else pos
201
+ local hsize = size/2
202
+ local points = {
203
+ cf * Vector3.new( hsize, 0, hsize),
204
+ cf * Vector3.new(-hsize, 0, hsize),
205
+ cf * Vector3.new(-hsize, 0, -hsize),
206
+ cf * Vector3.new( hsize, 0, -hsize),
207
+ cf * Vector3.new(0, height, 0),
208
+ }
209
+ wfh:AddPath({points[1], points[2], points[3], points[4], points[1], points[5], points[2]}, false)
210
+ wfh:AddPath({points[3], points[5], points[4]}, false)
211
+ end
212
+
213
+ local function drawCFrame(cf: CFrame, size: number, color: Color3)
214
+ size = size or 1
215
+ local color3 = wfh.Color3
216
+ local pos = cf.Position
217
+ if color ~= nil then
218
+ setColor(color)
219
+ drawLine(pos, pos + cf.RightVector * size)
220
+ drawLine(pos, pos + cf.UpVector * size)
221
+ drawLine(pos, pos + -cf.LookVector * size)
222
+ else
223
+ setColor('red')
224
+ drawLine(pos, pos + cf.RightVector * size)
225
+ setColor('green')
226
+ drawLine(pos, pos + cf.UpVector * size)
227
+ setColor('blue')
228
+ drawLine(pos, pos + -cf.LookVector * size)
229
+ end
230
+ wfh.Color3 = color3
231
+ end
232
+
233
+ local function helper_formatText(...)
234
+ local args = {...}
235
+ local text = ''
236
+ for _, v in ipairs(args) do
237
+ local str
238
+ if typeof(v) == 'string' then
239
+ str = v
240
+ elseif typeof(v) == 'number' then
241
+ str = string.format('%.3f', v)
242
+ elseif typeof(v) == 'Vector3' then
243
+ str = string.format('(%.3f, %.3f, %.3f)', v.x, v.y, v.z)
244
+ elseif typeof(v) == 'CFrame' then
245
+ local rx,ry,rz = v:ToOrientation()
246
+ rx, ry, rz = math.deg(rx), math.deg(ry), math.deg(rz)
247
+ local pos = v.Position
248
+ str = string.format('pos=(%.3f, %.3f, %.3f) rot=(%.3f, %.3f, %.3f)', pos.x, pos.y, pos.z, rx, ry, rz)
249
+ else
250
+ str = tostring(v)
251
+ end
252
+ text = text .. ' ' .. str
253
+ end
254
+ return text
255
+ end
256
+
257
+ local function drawText(position: Vector3, ...)
258
+ local args = {...}
259
+ local text = helper_formatText(unpack(args))
260
+ local size = nil
261
+ wfh:AddText(position, text, size)
262
+ end
263
+
264
+ local function log(...)
265
+ if label then
266
+ local args = {...}
267
+ local text = helper_formatText(unpack(args))
268
+ label.Text = label.Text .. '\n' .. text
269
+ end
270
+ end
271
+
272
+ local function helper_drawHit(hit: RaycastResult)
273
+ drawCircle(hit.Position, 0.15, hit.Normal)
274
+ drawRay(hit.Position, hit.Normal * 0.3)
275
+ end
276
+
277
+ local function helper_drawRaycast(cf: CFrame, direction: Vector3, result: RaycastResult, shape: number, size: number | Vector3)
278
+ local color3 = wfh.Color3
279
+ local travel
280
+ if result then
281
+ setColor(hitColor)
282
+ travel = direction.Unit * result.Distance
283
+ helper_drawHit(result)
284
+ else
285
+ setColor(missColor)
286
+ travel = direction
287
+ end
288
+ if shape == 1 then
289
+ drawSphere(cf, size)
290
+ drawSphere(cf + travel, size)
291
+ elseif shape == 2 then
292
+ drawCube(cf, size)
293
+ drawCube(cf + travel, size)
294
+ end
295
+ drawRay(cf.Position, travel)
296
+ wfh.Color3 = color3
297
+ end
298
+
299
+ local function drawRaycast(origin: Vector3, direction: Vector3, result: RaycastResult)
300
+ helper_drawRaycast(CFrame.new(origin), direction, result, 0)
301
+ end
302
+
303
+ local function drawSpherecast(origin: Vector3, radius: number, direction: Vector3, result: RaycastResult)
304
+ helper_drawRaycast(CFrame.lookAlong(origin, direction), direction, result, 1, radius)
305
+ end
306
+
307
+ local function drawBlockcast(cf: CFrame, size: Vector3, direction: Vector3, result: RaycastResult)
308
+ helper_drawRaycast(cf, direction, result, 2, size)
309
+ end
310
+
311
+ function Gizmos:setColor(color: string | Color3)
312
+ table.insert(commands, function()
313
+ setColor(color)
314
+ end)
315
+ end
316
+
317
+ function Gizmos:setTransparency(value: number)
318
+ table.insert(commands, function()
319
+ setTransparency(value)
320
+ end)
321
+ end
322
+
323
+ function Gizmos:drawLine(from: Vector3, to: Vector3)
324
+ table.insert(commands, function()
325
+ drawLine(from, to)
326
+ end)
327
+ end
328
+
329
+ function Gizmos:drawRay(origin: Vector3, direction: Vector3)
330
+ table.insert(commands, function()
331
+ drawRay(origin, direction)
332
+ end)
333
+ end
334
+
335
+ function Gizmos:drawPath(points: {Vector3}, closed: boolean?, dotsSize: number?)
336
+ table.insert(commands, function()
337
+ drawPath(points, closed, dotsSize)
338
+ end)
339
+ end
340
+
341
+ function Gizmos:drawPoint(position: Vector3, size: number?)
342
+ table.insert(commands, function()
343
+ drawPoint(position, size)
344
+ end)
345
+ end
346
+
347
+ function Gizmos:drawCube(position: Vector3 | CFrame, size: Vector3)
348
+ table.insert(commands, function()
349
+ drawCube(position, size)
350
+ end)
351
+ end
352
+
353
+ function Gizmos:drawCircle(position: Vector3, radius: number, normal: Vector3?)
354
+ table.insert(commands, function()
355
+ drawCircle(position, radius, normal)
356
+ end)
357
+ end
358
+
359
+ function Gizmos:drawSphere(position: Vector3 | CFrame, radius: number)
360
+ table.insert(commands, function()
361
+ drawSphere(position, radius)
362
+ end)
363
+ end
364
+
365
+ function Gizmos:drawPyramid(position: Vector3 | CFrame, size: number, height: number)
366
+ table.insert(commands, function()
367
+ drawPyramid(position, size, height)
368
+ end)
369
+ end
370
+
371
+ function Gizmos:drawCFrame(cf: CFrame, size: number?, color: Color3?)
372
+ table.insert(commands, function()
373
+ drawCFrame(cf, size, color)
374
+ end)
375
+ end
376
+
377
+ function Gizmos:drawText(position: Vector3, ...)
378
+ local args = {...}
379
+ table.insert(commands, function()
380
+ drawText(position, unpack(args))
381
+ end)
382
+ end
383
+
384
+ function Gizmos:log(...)
385
+ local args = {...}
386
+ table.insert(commands, function()
387
+ log(unpack(args))
388
+ end)
389
+ end
390
+
391
+ function Gizmos:drawRaycast(origin: Vector3, direction: Vector3, result: RaycastResult)
392
+ table.insert(commands, function()
393
+ drawRaycast(origin, direction, result)
394
+ end)
395
+ end
396
+
397
+ function Gizmos:drawSpherecast(origin: Vector3, radius: number, direction: Vector3, result: RaycastResult)
398
+ table.insert(commands, function()
399
+ drawSpherecast(origin, radius, direction, result)
400
+ end)
401
+ end
402
+
403
+ function Gizmos:drawBlockcast(cf: CFrame, size: Vector3, direction: Vector3, result: RaycastResult)
404
+ table.insert(commands, function()
405
+ drawBlockcast(cf, size, direction, result)
406
+ end)
407
+ end
408
+
409
+ function Gizmos:addToPath(name: string, position: Vector3, dotsSize: number?)
410
+ if not trailers[name] then
411
+ trailers[name] = Trailer.new()
412
+ end
413
+ trailers[name]:addValue(position)
414
+ table.insert(commands, function()
415
+ drawPath(trailers[name]:getValues(), false, dotsSize)
416
+ end)
417
+ end
418
+
419
+ function Gizmos:forceUpdate()
420
+ wfh:Clear()
421
+ if label then
422
+ label.Text = ''
423
+ end
424
+ for _, command in ipairs(commands) do
425
+ command()
426
+ end
427
+ commands = {}
428
+ end
429
+
430
+ function Gizmos:test()
431
+ local p = Vector3.new(0, 0, 10)
432
+ local x, y, z = Vector3.xAxis, Vector3.yAxis, Vector3.zAxis
433
+ local function n() p += Vector3.xAxis*2 end
434
+
435
+ Gizmos:setColor('white')
436
+ Gizmos:setTransparency(0)
437
+ Gizmos:drawLine(p, p + y) n()
438
+ Gizmos:drawRay(p, y) n()
439
+ Gizmos:drawPath({ p+Vector3.new(-0.3,0,-0.3), p+Vector3.new(0.4,0,0), p+Vector3.new(0.1,0,0.5), p+Vector3.new(0.6,0,0.9)}) n()
440
+ Gizmos:drawPoint(p) n()
441
+ Gizmos:drawCube(p + y*0.5, Vector3.one) n()
442
+ Gizmos:drawCircle(p, 0.5) n()
443
+ Gizmos:drawSphere(p+y*0.5, 0.5) n()
444
+ Gizmos:drawPyramid(p, 1, 1) n()
445
+ Gizmos:drawCFrame(CFrame.new(p)) n()
446
+ Gizmos:drawText(p, 'Hello') n()
447
+ Gizmos:drawRaycast(p, z, nil) n()
448
+ Gizmos:drawSpherecast(p, 0.3, z, nil) n()
449
+ Gizmos:drawBlockcast(CFrame.new(p), Vector3.one*0.6, z, nil) n()
450
+ Gizmos:log('Log')
451
+
452
+ local colors = {'red', 'orange', 'yellow', 'green', 'cyan', 'blue', 'purple', 'magenta', 'black', 'gray', 'white'}
453
+ p = Vector3.new(0, 0, 12)
454
+ for _, color in ipairs(colors) do
455
+ Gizmos:setColor(color)
456
+ Gizmos:drawCircle(p, 0.15)
457
+ p += Vector3.xAxis*1
458
+ end
459
+ end
460
+
461
+ findOrMakeGizmos()
462
+ findOrMakeLabel()
463
+
464
+ local function Update(dt)
465
+ local t = tick()
466
+ if t ~= wfh:GetAttribute('lastUpdateTime') then
467
+ wfh:SetAttribute('lastUpdateTime', t)
468
+ if Gizmos.clear then
469
+ wfh:Clear()
470
+ if label then
471
+ label.Text = ''
472
+ end
473
+ end
474
+ end
475
+ for _, command in ipairs(commands) do
476
+ command()
477
+ end
478
+ commands = {}
479
+ end
480
+
481
+ local RunService = game:GetService('RunService')
482
+ if RunService:IsRunning() then
483
+ RunService:BindToRenderStep('name', Enum.RenderPriority.Camera.Value-1, Update)
484
+ end
485
+
486
+ return Gizmos
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@rbxts/gizmos",
3
+ "version": "1.0.0",
4
+ "description": "TypeScript port of sg3cko's Gizmos library - Debug drawing utilities for Roblox including shapes, raycasts, paths, and world-space text.",
5
+ "main": "out/init.lua",
6
+ "scripts": {
7
+ "build": "rbxtsc",
8
+ "watch": "rbxtsc -w",
9
+ "prepublishOnly": "npm run build"
10
+ },
11
+ "keywords": [],
12
+ "author": "Colin Miller",
13
+ "license": "MIT",
14
+ "type": "commonjs",
15
+ "types": "out/index.d.ts",
16
+ "files": [
17
+ "out",
18
+ "!**/*.tsbuildinfo"
19
+ ],
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/cmmiller26/rbxts-gizmos.git"
23
+ },
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "devDependencies": {
28
+ "@rbxts/compiler-types": "^3.0.0-types.0",
29
+ "@rbxts/types": "^1.0.891",
30
+ "@typescript-eslint/eslint-plugin": "^8.46.4",
31
+ "@typescript-eslint/parser": "^8.46.4",
32
+ "eslint": "^9.39.1",
33
+ "eslint-config-prettier": "^10.1.8",
34
+ "eslint-plugin-prettier": "^5.5.4",
35
+ "eslint-plugin-roblox-ts": "^1.3.0",
36
+ "prettier": "^3.6.2",
37
+ "roblox-ts": "^3.0.0",
38
+ "typescript": "^5.9.3"
39
+ }
40
+ }