Ceive ImGizmo - A debug gizmo library


image

Used this library to visualize my block placement algorithm

4 Likes

Can you explain more in detail how to use this library?
in the example you provided, the cylinder isn’t really appear in game.

Can you please share the code your using, and also if your using it on the server or client

To those interested using this with roblox-ts, heres the d.ts file:

interface Ceive {
    GetPoolSize: () => number;
    PushProperty: (Property: string, Value: any) => void;
    PopProperty: (Property: string) => any;
    SetStyle: (Color: Color3, Transparency: number, AlwaysOnTop: boolean) => void;
    DoCleaning: () => void;
    ScheduleCleaning: () => void;
    AddDebrisInSeconds: (Seconds: number, Callback: () => void) => void;
    AddDebrisInFrames: (Frames: number, Callback: () => void) => void;
    TweenProperties: (Properties: Map<string, any>, Goal: Map<string, any>, TweenInfo: TweenInfo) => void;
    Init: () => void;
    SetEnabled: (Value: boolean) => void;

    Ray: {
        Draw(Origin: Vector3, End: Vector3): void;
        Create(Origin: Vector3, End: Vector3): {Origin: Vector3, End: Vector3, Color3: Color3, AlwaysOnTop: boolean, Transparency: number};
    }

    Box: {
        Draw(Transform: CFrame, Size: Vector3, DrawTriangles: boolean): void;
	    Create(Transform: CFrame, Size: Vector3, DrawTriangles: boolean): {Transform: CFrame, Size: Vector3, DrawTriangles: boolean, Color3: Color3, AlwaysOnTop: boolean, Transparency: number, Enabled: boolean, Destroy: boolean};
    }

    Plane: {
        Draw(Position: Vector3, Normal: Vector3, Size: Vector3): void;
        Create(Position: Vector3, Normal: Vector3, Size: Vector3): {Position: Vector3, Normal: Vector3, Size: Vector3, DrawTriangles: boolean, Color3: Color3, AlwaysOnTop: boolean, Transparency: number, Enabled: boolean, Destroy: boolean}
    }
    
    Wedge: {
        Draw(Transform: CFrame, Size: Vector3, DrawTriangles: boolean): void;
        Create(Transform: CFrame, Size: Vector3, DrawTriangles: boolean): {Transform: CFrame, Size: Vector3, DrawTriangles: boolean, Color3: Color3, AlwaysOnTop: boolean, Transparency: number, Enabled: boolean, Destroy: boolean}
    }
    
    Circle: {
        Draw(Transform: CFrame, Radius: number, Subdivisions: number, ConnectToStart?: boolean): void;
        Create(Transform: CFrame, Radius: number, Subdivisions: number, ConnectToStart?: boolean): {Transform: CFrame, Radius: number, Subdivisions: number, ConnectToStart?: boolean, Color3: Color3, AlwaysOnTop: boolean, Transparency: number, Enabled: boolean, Destroy: boolean}
    }
    
    Sphere: {
        Draw(Transform: CFrame, Radius: number, Subdivisions: number, Angle: number): void;
        Create(Transform: CFrame, Radius: number, Subdivisions: number, Angle: number): {Transform: CFrame, Radius: number, Subdivisions: number, Angle: number, Color3: Color3, AlwaysOnTop: boolean, Transparency: number, Enabled: boolean, Destroy: boolean}
    }
    
    Cylinder: {
        Draw(Transform: CFrame, Radius: number, Length: number, Subdivisions: number): void;
        Create(Transform: CFrame, Radius: number, Length: number, Subdivisions: number): {Transform: CFrame, Radius: number, Length: number, Subdivisions: number, Color3: Color3, AlwaysOnTop: boolean, Transparency: number, Enabled: boolean, Destroy: boolean}
    }
    
    Capsule: {
        Draw(Transform: CFrame, Radius: number, Length: number, Subdivisions: number): void;
        Create(Transform: CFrame, Radius: number, Length: number, Subdivisions: number): {Transform: CFrame, Radius: number, Length: number, Subdivisions: number, Color3: Color3, AlwaysOnTop: boolean, Transparency: number, Enabled: boolean, Destroy: boolean}
    }
    
    Cone: {
        Draw(Transform: CFrame, Radius: number, Length: number, Subdivisions: number): void;
        Create(Transform: CFrame, Radius: number, Length: number, Subdivisions: number): {Transform: CFrame, Radius: number, Length: number, Subdivisions: number, Color3: Color3, AlwaysOnTop: boolean, Transparency: number, Enabled: boolean, Destroy: boolean}
    }
    
    Arrow: {
        Draw(Origin: Vector3, End: Vector3, Radius: number, Length: number, Subdivisions: number): void;
        Create(Origin: Vector3, End: Vector3, Radius: number, Length: number, Subdivisions: number): {Origin: Vector3, End: Vector3, Radius: number, Length: number, Subdivisions: number, Color3: Color3, AlwaysOnTop: boolean, Transparency: number, Enabled: boolean, Destroy: boolean}
    }
    
    Mesh: {
        Draw(Transform: CFrame, Size: Vector3, Vertices: {}, Faces: {}): void;
        Create(Transform: CFrame, Size: Vector3, Vertices: {}, Faces: {}): {Transform: CFrame, Size: Vector3, Vertices: {}, Faces: {}, Color3: Color3, AlwaysOnTop: boolean, Transparency: number, Enabled: boolean, Destroy: boolean}
    }
    
    Line: {
        Draw(Transform: CFrame, Length: number): void;
        Create(Transform: CFrame, Length: number): {Transform: CFrame, Length: number, Color3: Color3, AlwaysOnTop: boolean, Transparency: number, Enabled: boolean, Destroy: boolean}
    }
    
    VolumeCone: {
        Draw(Transform: CFrame, Radius: number, Length: number): void;
        Create(Transform: CFrame, Radius: number, Length: number): {Transform: CFrame, Radius: number, Length: number, Color3: Color3, AlwaysOnTop: boolean, Transparency: number, Enabled: boolean, Destroy: boolean}
    }
    
    VolumeBox: {
        Draw(Transform: CFrame, Size: Vector3): void;
        Create(Transform: CFrame, Size: Vector3): {Transform: CFrame, Size: Vector3, Color3: Color3, AlwaysOnTop: boolean, Transparency: number, Enabled: boolean, Destroy: boolean}
    }
    
    VolumeSphere: {
        Draw(Transform: CFrame, Radius: number): void;
        Create(Transform: CFrame, Radius: number): {Transform: CFrame, Radius: number, Color3: Color3, AlwaysOnTop: boolean, Transparency: number, Enabled: boolean, Destroy: boolean}
    }
    
    VolumeCylinder: {
        Draw(Transform: CFrame, Radius: number, Length: number, InnerRadius?: number, Angle?: number): void;
        Create(Transform: CFrame, Radius: number, Length: number, InnerRadius?: number, Angle?: number): {Transform: CFrame, Radius: number, Length: number, InnerRadius?: number, Angle?: number, Color3: Color3, AlwaysOnTop: boolean, Transparency: number, Enabled: boolean, Destroy: boolean}
    }
    
    VolumeArrow: {
        Draw(Origin: Vector3, End: Vector3, CylinderRadius: number, ConeRadius: number, Length: number, UseCylinder?: boolean): void;
        Create(Origin: Vector3, End: Vector3, CylinderRadius: number, ConeRadius: number, Length: number, UseCylinder?: boolean): {Origin: Vector3, End: Vector3, CylinderRadius: number, ConeRadius: number, Length: number, UseCylinder?: boolean, Color3: Color3, AlwaysOnTop: boolean, Transparency: number, Enabled: boolean, Destroy: boolean}
    }
}

declare const Ceive: Ceive;

export = Ceive;

tried both.

used this:

Gizmo.PushProperty("Color3", Color3.new(0.184314, 0.184314, 1))
Gizmo.Cylinder:Draw(CFrame.new(0, 10, 0) * CFrame.Angles(0, math.rad(25), 0), 2, 4, 20) -- Location: CFrame, Radius: number, Length: number, Subdivisions: number

even without defining the variables didn’t found the gizmo (didn’t touch the exmaple you provided basically)

Are you doing this on the server or client? And did you call Gizmo.Init()?
Are you running the code in RenderStepped or Heartbeat?

I also recommend you check out the demo place (uncopylocked) for more detailed examples.

Why don’t you call the initialization code in the module itself
e.g

-- Gizmo.lua
local ImGizmo = {
   ...
}

function ImGizo.PushProperty(...)
   ...
end
...

init() -- run Gizmo.Init() here
return ImGizmo

now when users require ImGizmo

local Gizmo = require(...)

...
-- In a RenderStepped loop
izmo.PushProperty("Color3", Color3.new(0.184314, 0.184314, 1))
Gizmo.Cylinder:Draw(CFrame.new(0, 10, 0) * CFrame.Angles(0, math.rad(25), 0), 2, 4, 20)

they needn’t run Gizmo.Init() right after requiring it so it can avoid problems like users not realizing they need that for the library to work

iirc module scripts are only ran once on the first require and the return value is cached for subsequent require()s to the same modulescript.

This means for a supposed ToastNotificationManager, the gui initialization code (which may look like local screenGui = Instance.new("ScreenGui", PlayerGui) ... ) is only ran once, no matter if local scripts Admin, DataStoreErrorDisplayer and PoorPingNotifier all require it.

or in this case, the gizmo init stuff is ran only once, no matter if say SwordHitBoxes, CameraSystem and ThrowingKnives each require() the module

1 Like

Oh yeah I never really thought about that, I’ll switch it over in the next release

i’m loving it so far, would be nice if there also was a function for drawing strings though

1 Like

v3.3.0

v3.3.0 doesnt bring any new features just wally support.

2 Likes

The current behaviour is better since (in my opinion) requiring a module shouldn’t have any side effects.

Ive decided against this mainly because I myself have had situations where I’ve not wanted to init the library under certain situations (out of studio, not in debug mode etc etc)

v3.4.0

Few bug fixes + 2 extra features

v3.4.1

Forgot to add a type

Wonderful module, needed an efficient way to preview my raycasts and it worked wonderfully:

Only 2 issues I found is that the sphere shape crashes your studio if you give it an angle of 0 (which took me a bit to notice), and that there is no BasePart support (which would be super useful now that generalized shapecasts are a thing)

That aside, tysm for making this, i’m sure I’ll find more uses for it.


Here’s the example place from the gif in case anyone finds it of use (it’s wrapped it into a module for ease of usage):
CastVisualizer.rbxl (70.5 KB)

And here’s a how to use it:


Edit: Needed a strict typed version of this so I gave it a small cleanup, here it is:
CastVisualizer 1.1.rbxl (74.5 KB)

API should be the same but the visualize functions are now separate (also updated Ceive ImGizmo to the latest version).

2 Likes

Sphere crashing studio at angle 0 is odd, however there wont be support for a generic basepart gizmo. It’s out of the scope of Ceive ImGizmo. Not to mention atm it’s not even possible.

1 Like

neat so how did you visualize the raycasts? and how would this work with shapecasts

Check the module’s code, when nothing is detected I simply call gizmo in the position the raycast is intended to reach (origin + direction), when something is detected the raycast.position is used instead.

Not sure regarding gizmo as I haven’t used ā€œWireframeHandleAdornmentsā€ myself (if OP says it’s not possible, i’m guessing it isn’t), but module wise it’d work the exact same way shepecasts work, it’d take the basepart and offset the ā€œgizmoā€ in the intended direction (which can be done without gizmo making a clone of the part, but I prefer keeping it consistent so just use the available shapes and it’ll still somewhat help you visualize the shapecast).

2 Likes

How can I render the face surrounded by each line?