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:

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?