Gizmos

Gizmos are the editor's in-world visualization and manipulation layer. They draw lines, boxes, spheres, and labels over the Scene View, show what built-in components are doing (camera frustums, light shapes, collider bounds), and give you an interactive transform gizmo to move, rotate, and scale objects directly in the viewport.


The viewport has its own free-look camera, independent of the game's cameras. Hold the right mouse button to look around; while held:

  • WASD moves, Q/E drop and raise, Shift accelerates.
  • The mouse wheel dollies forward/back at any time.
  • F frames the camera on the current selection.

The Camera ▾ menu in the toolbar tunes the navigation feel — Move speed, Look sensitivity, and Zoom speed (handy when the wheel dolly feels too aggressive). Your settings persist between sessions via the editor Settings store.

Selecting objects

Click an object in the Scene View to select it — meshes are picked by a ray cast against the mesh's actual bounds, and lights/cameras/empties are picked by clicking their icon. Clicking empty space clears the selection. (You can also select from the Scene Tree, as before.)

The transform gizmo

Select an object and a colored handle appears at its origin in the Scene View. The handle follows your camera at a constant on-screen size.

Mode Hotkey Handle Drag effect
Move W Three axis arrows (X red, Y green, Z blue) Slides the object along that axis
Rotate E Three axis circles Spins the object around that axis
Scale R Three axis lines with cube tips Scales the object along that axis

Hover an axis to highlight it, then drag to manipulate. Each drag is a single undo step (Ctrl+Z). The mode buttons live in the Scene View toolbar.

Snapping

Toggle Snap in the toolbar to constrain drags to fixed increments — 0.5 units for moves, 15° for rotations, 0.25 for scale. Snapping rounds the change you make, so you can nudge values onto a clean grid.


Component gizmos

Built-in components draw their own visualizers, filtered by the Gizmos ▾ menu in the toolbar:

  • Cameras — a frustum outline plus a camera icon. The frustum is drawn only when that camera is selected.
  • Lights — directional lights show a sun disc and parallel rays; point lights show a wire sphere at their range; spot lights show a wire cone. The shape is drawn only for the selected light, so a scene full of lights stays readable; every light always shows a bulb icon tinted to its color.
  • Colliders — a wire box around the collider bounds.
  • Icons — the billboard icons for lights/cameras (and custom types).
  • Selection outline — an orange box around the selected object's mesh, hugging the mesh's real bounds. Immaterial nodes (lights, cameras, empties) have no spatial extent, so they get no outline — their icon and the transform handles mark the selection instead.
  • Grid — a ground grid on the XZ plane with brighter center axes.

Each type can be toggled independently, so you can declutter the viewport while keeping the visuals you care about.


The Gizmos API

Gizmos are recorded into a plain‑data command buffer (engine.Gizmos) — no GPU or GUI dependencies — so any component, including your own scripts, can record them. Every shape decomposes into colored line segments.

const engine = @import("engine");

fn draw(giz: *engine.Gizmos, center: engine.Vector3) void {
    giz.setColor(.green);
    giz.wireSphere(center, 0.5);

    giz.setColor(.yellow);
    giz.arrow(center, center.add(.{ .x = 0, .y = 2, .z = 0 }));

    giz.setColor(engine.Gizmos.Color.rgb(0.2, 0.6, 1.0));
    giz.box(center, .{ .x = 1, .y = 1, .z = 1 });
    giz.label(center, "spawn point");
}

Available primitives: line, lineW, ribbon, ray, polyline, arrow, tube, box, wireCube (matrix-oriented), circle, wireSphere, wireCone, frustum, and label. setColor, setLineWidth, and setMatrix apply to everything recorded after them; setMatrix lets you draw in an object's local space.

Line thickness

Lines have a screen-space thickness in pixels, carried per vertex — the renderer expands each segment into a camera-facing quad, so a line stays the same width however far the camera sits. Set a uniform width with setLineWidth, or vary it per endpoint:

giz.setLineWidth(3);                 // 3px for everything after this
giz.arrow(a, b);                     // a fat, easy-to-read arrow

// A comet trail that tapers to nothing — width per point.
const pts = [_]engine.Vector3{ head, mid, tail };
const widths = [_]f32{ 8, 4, 0 };
giz.ribbon(&pts, &widths);

lineW(a, b, wa, wb) draws a single segment tapering from wa to wb; ribbon(points, widths) chains those into a variable-width strip. The transform-gizmo move/scale handles use setLineWidth so they read (and grab) as solid bars rather than 1px threads.

Custom component gizmos, icons & layers

Extensions register against a component type name with the editor's gizmo system — a drawer (records lines/labels), a billboard icon, and/or a visibility layer (Unity-style):

GizmoSystem.registerGizmo("WaypointPath", drawWaypoints);
GizmoSystem.registerIcon("WaypointPath", dvui.entypo.flag);
GizmoSystem.setLayer("WaypointPath", "Navigation");

fn drawWaypoints(giz: *engine.Gizmos, node: *const engine.SceneNode, comp: *const engine.Component) void {
    _ = comp;
    giz.setColor(.cyan);
    giz.wireSphere(node.transform.position, 0.25);
}

Custom gizmos and icons honor the Custom / Icons visibility toggles alongside the built-ins.


Notes

  • Gizmos render only in the editor viewport, never in the shipped game.
  • World gizmos are depth-tested against the scene; transform handles always draw on top so they stay grabbable.
  • Rotation handles rotate around world axes; on already-rotated objects the result is applied to the matching Euler angle.

← All docs Edit this page