@rbxts/gizmos 1.0.0 → 1.2.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/README.md CHANGED
@@ -41,7 +41,7 @@ Gizmos.log("Frame:", tick());
41
41
 
42
42
  ## Features
43
43
 
44
- - **Shapes**: Lines, rays, paths, points, cubes, circles, spheres, pyramids
44
+ - **Shapes**: Lines, rays, paths, points, cubes, circles, spheres, pyramids, cones
45
45
  - **Raycasts**: Visualize raycasts, spherecasts, and blockcasts with hit detection
46
46
  - **Text**: World-space and on-screen text rendering
47
47
  - **Colors**: Built-in color presets (red, green, blue, yellow, cyan, magenta, orange, purple, white, gray, black)
@@ -62,6 +62,7 @@ Gizmos.log("Frame:", tick());
62
62
  - `drawCircle(position: Vector3, radius: number, normal?: Vector3)` - Draw circle
63
63
  - `drawSphere(position: Vector3 | CFrame, radius: number)` - Draw sphere
64
64
  - `drawPyramid(position: Vector3 | CFrame, size: number, height: number)` - Draw pyramid
65
+ - `drawCone(apex: Vector3, direction: Vector3, range: number, halfAngleDeg: number, segments?: number)` - Draw cone (apex + axis + slant range + half-angle); resolution adapts to the cone's shape, with an optional `segments` override
65
66
  - `drawCFrame(cf: CFrame, size?: number, color?: Color3)` - Draw CFrame axes
66
67
 
67
68
  ### Raycasts
package/out/index.d.ts CHANGED
@@ -8,6 +8,12 @@
8
8
  */
9
9
 
10
10
  interface Gizmos {
11
+ /**
12
+ * Whether gizmos are enabled and will be rendered
13
+ * @default true
14
+ */
15
+ enabled: boolean;
16
+
11
17
  /**
12
18
  * Whether to automatically clear gizmos each frame
13
19
  * @default true
@@ -85,6 +91,20 @@ interface Gizmos {
85
91
  */
86
92
  drawPyramid(position: Vector3 | CFrame, size: number, height: number): void;
87
93
 
94
+ /**
95
+ * Draw a wireframe cone with its apex at a point, opening along a direction.
96
+ *
97
+ * Wider cones automatically get more slant lines and intermediate cross-section
98
+ * rings so short/wide shapes (e.g. a melee hit volume) read as a solid 3D cone
99
+ * rather than a sparse X.
100
+ * @param apex Tip of the cone (e.g. the attacker's position)
101
+ * @param direction Axis the cone opens along (need not be normalized)
102
+ * @param range Slant length — straight-line distance from the apex to the base rim
103
+ * @param halfAngleDeg Half-angle of the cone in degrees (axis to slant edge)
104
+ * @param segments Optional base-rim resolution override; defaults to a value adapted to the rim size (clamped 16–48)
105
+ */
106
+ drawCone(apex: Vector3, direction: Vector3, range: number, halfAngleDeg: number, segments?: number): void;
107
+
88
108
  /**
89
109
  * Draw a CFrame as colored axes (red = right, green = up, blue = -look)
90
110
  * @param cf CFrame to visualize
package/out/init.lua CHANGED
@@ -7,6 +7,7 @@ local trailers = {}
7
7
 
8
8
  local hitColor, missColor = 'green', 'red'
9
9
 
10
+ Gizmos.enabled = true
10
11
  Gizmos.clear = true
11
12
 
12
13
  local colors = {
@@ -174,19 +175,20 @@ local function drawCube(pos: Vector3 | CFrame, size: Vector3)
174
175
  })
175
176
  end
176
177
 
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)
178
+ local function helper_circlePoints(cf: CFrame, radius: number, segments: number): {Vector3}
181
179
  local angle = 2 * math.pi / segments
182
-
183
180
  local points = {}
184
181
  for i = 1, segments do
185
182
  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)
183
+ table.insert(points, cf:PointToWorldSpace(localpoint))
188
184
  end
189
- wfh:AddPath(points, true)
185
+ return points
186
+ end
187
+
188
+ local function drawCircle(pos: Vector3, radius: number, normal: Vector3?)
189
+ normal = normal or Vector3.yAxis
190
+ local cf = CFrame.lookAlong(pos, normal)
191
+ wfh:AddPath(helper_circlePoints(cf, radius, 16), true)
190
192
  end
191
193
 
192
194
  local function drawSphere(pos: Vector3 | CFrame, radius: number)
@@ -210,6 +212,40 @@ local function drawPyramid(pos: Vector3 | CFrame, size: number, height: number)
210
212
  wfh:AddPath({points[3], points[5], points[4]}, false)
211
213
  end
212
214
 
215
+ local function drawCone(apex: Vector3, direction: Vector3, range: number, halfAngleDeg: number, segments: number?)
216
+ local dir = direction.Unit
217
+ local halfAngle = math.rad(halfAngleDeg)
218
+ local height = range * math.cos(halfAngle)
219
+ local radius = range * math.sin(halfAngle)
220
+ local baseCenter = apex + dir * height
221
+ local cf = CFrame.lookAlong(baseCenter, dir)
222
+
223
+ -- Base resolution scales with the rim size so wide cones stay smooth,
224
+ -- clamped so tiny cones aren't overdrawn and huge ones aren't sparse.
225
+ segments = segments or math.clamp(math.round(radius * 6), 16, 48)
226
+
227
+ -- Base rim.
228
+ local rim = helper_circlePoints(cf, radius, segments)
229
+ wfh:AddPath(rim, true)
230
+
231
+ -- Slant lines (rim -> apex). Wider cones get more so the volume reads as a
232
+ -- cone rather than a sparse X; narrow cones fall back to 4 like before.
233
+ local slantCount = math.clamp(math.round(halfAngleDeg / 3.75), 4, 16)
234
+ for j = 0, slantCount - 1 do
235
+ wfh:AddLine(apex, rim[math.floor(j / slantCount * segments) + 1])
236
+ end
237
+
238
+ -- Intermediate cross-section rings help a wide/short cone read as a solid
239
+ -- volume; narrow cones get none. Each ring sits at fraction t of the height,
240
+ -- where the cone radius is t * radius.
241
+ local ringCount = math.clamp(math.floor(halfAngleDeg / 22.5), 0, 3)
242
+ for k = 1, ringCount do
243
+ local t = k / (ringCount + 1)
244
+ local ringCf = CFrame.lookAlong(apex + dir * height * t, dir)
245
+ wfh:AddPath(helper_circlePoints(ringCf, radius * t, segments), true)
246
+ end
247
+ end
248
+
213
249
  local function drawCFrame(cf: CFrame, size: number, color: Color3)
214
250
  size = size or 1
215
251
  local color3 = wfh.Color3
@@ -368,6 +404,12 @@ function Gizmos:drawPyramid(position: Vector3 | CFrame, size: number, height: nu
368
404
  end)
369
405
  end
370
406
 
407
+ function Gizmos:drawCone(apex: Vector3, direction: Vector3, range: number, halfAngleDeg: number, segments: number?)
408
+ table.insert(commands, function()
409
+ drawCone(apex, direction, range, halfAngleDeg, segments)
410
+ end)
411
+ end
412
+
371
413
  function Gizmos:drawCFrame(cf: CFrame, size: number?, color: Color3?)
372
414
  table.insert(commands, function()
373
415
  drawCFrame(cf, size, color)
@@ -442,6 +484,7 @@ function Gizmos:test()
442
484
  Gizmos:drawCircle(p, 0.5) n()
443
485
  Gizmos:drawSphere(p+y*0.5, 0.5) n()
444
486
  Gizmos:drawPyramid(p, 1, 1) n()
487
+ Gizmos:drawCone(p, y, 1, 30) n()
445
488
  Gizmos:drawCFrame(CFrame.new(p)) n()
446
489
  Gizmos:drawText(p, 'Hello') n()
447
490
  Gizmos:drawRaycast(p, z, nil) n()
@@ -456,12 +499,35 @@ function Gizmos:test()
456
499
  Gizmos:drawCircle(p, 0.15)
457
500
  p += Vector3.xAxis*1
458
501
  end
502
+
503
+ -- Cones from narrow/long to wide/short, including the melee hit-volume case
504
+ -- (range 7, halfAngle 45). Each should read clearly as a 3D cone.
505
+ Gizmos:setColor('cyan')
506
+ Gizmos:drawCone(Vector3.new(0, 0, 16), y, 4, 10) -- narrow / long
507
+ Gizmos:drawCone(Vector3.new(8, 0, 16), y, 4, 30)
508
+ Gizmos:drawCone(Vector3.new(20, 0, 16), y, 7, 45) -- wide / short (melee)
509
+ Gizmos:drawCone(Vector3.new(34, 0, 16), y, 4, 60) -- very wide
459
510
  end
460
511
 
461
512
  findOrMakeGizmos()
462
513
  findOrMakeLabel()
463
514
 
515
+ local previousEnabled = true
516
+
464
517
  local function Update(dt)
518
+ if not Gizmos.enabled then
519
+ if previousEnabled then
520
+ -- Just disabled, clear everything
521
+ wfh:Clear()
522
+ if label then
523
+ label.Text = ''
524
+ end
525
+ previousEnabled = false
526
+ end
527
+ commands = {}
528
+ return
529
+ end
530
+ previousEnabled = true
465
531
  local t = tick()
466
532
  if t ~= wfh:GetAttribute('lastUpdateTime') then
467
533
  wfh:SetAttribute('lastUpdateTime', t)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rbxts/gizmos",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "TypeScript port of sg3cko's Gizmos library - Debug drawing utilities for Roblox including shapes, raycasts, paths, and world-space text.",
5
5
  "main": "out/init.lua",
6
6
  "scripts": {