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.
Navigating the Scene View
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.