GUI callbacks

Attach event handlers to GUI elements for real-time interaction.

This example demonstrates how to create responsive interfaces using GUI callbacks. Callbacks are functions that execute automatically when users interact with controls, enabling real-time updates to the 3D scene.

Key callback methods:

Features demonstrated:

The pattern shown here—connecting GUI controls to scene updates via callbacks—is fundamental for building interactive 3D applications with viser.

Source: examples/02_gui/01_callbacks.py

GUI callbacks

Code

  1import time
  2
  3import numpy as np
  4from typing_extensions import assert_never
  5
  6import viser
  7
  8
  9def main() -> None:
 10    server = viser.ViserServer()
 11
 12    gui_reset_scene_click = server.gui.add_button("Reset Scene on Click")
 13
 14    gui_reset_scene_hold = server.gui.add_button("Reset Scene on Hold")
 15
 16    gui_plane = server.gui.add_dropdown(
 17        "Grid plane", ("xz", "xy", "yx", "yz", "zx", "zy")
 18    )
 19
 20    def update_plane() -> None:
 21        server.scene.add_grid("/grid", width=10.0, height=20.0, plane=gui_plane.value)
 22
 23    gui_plane.on_update(lambda _: update_plane())
 24
 25    with server.gui.add_folder("Control"):
 26        gui_show_frame = server.gui.add_checkbox("Show Frame", initial_value=True)
 27        gui_show_everything = server.gui.add_checkbox(
 28            "Show Everything", initial_value=True
 29        )
 30        gui_axis = server.gui.add_dropdown("Axis", ("x", "y", "z"))
 31        gui_include_z = server.gui.add_checkbox("Z in dropdown", initial_value=True)
 32
 33        @gui_include_z.on_update
 34        def _(_) -> None:
 35            gui_axis.options = ("x", "y", "z") if gui_include_z.value else ("x", "y")
 36
 37        with server.gui.add_folder("Sliders"):
 38            gui_location = server.gui.add_slider(
 39                "Location", min=-5.0, max=5.0, step=0.05, initial_value=0.0
 40            )
 41            gui_num_points = server.gui.add_slider(
 42                "# Points", min=1000, max=200_000, step=1000, initial_value=10_000
 43            )
 44
 45    def draw_frame() -> None:
 46        axis = gui_axis.value
 47        if axis == "x":
 48            pos = (gui_location.value, 0.0, 0.0)
 49        elif axis == "y":
 50            pos = (0.0, gui_location.value, 0.0)
 51        elif axis == "z":
 52            pos = (0.0, 0.0, gui_location.value)
 53        else:
 54            assert_never(axis)
 55
 56        server.scene.add_frame(
 57            "/frame",
 58            wxyz=(1.0, 0.0, 0.0, 0.0),
 59            position=pos,
 60            show_axes=gui_show_frame.value,
 61            axes_length=5.0,
 62        )
 63
 64    def draw_points() -> None:
 65        num_points = gui_num_points.value
 66        server.scene.add_point_cloud(
 67            "/frame/point_cloud",
 68            points=np.random.normal(size=(num_points, 3)),
 69            colors=np.random.randint(0, 256, size=(num_points, 3)),
 70        )
 71
 72    # We can (optionally) also attach callbacks!
 73    # Here, we update the point clouds + frames whenever any of the GUI items are updated.
 74    gui_show_frame.on_update(lambda _: draw_frame())
 75    gui_show_everything.on_update(
 76        lambda _: server.scene.set_global_visibility(gui_show_everything.value)
 77    )
 78    gui_axis.on_update(lambda _: draw_frame())
 79    gui_location.on_update(lambda _: draw_frame())
 80    gui_num_points.on_update(lambda _: draw_points())
 81
 82    @gui_reset_scene_click.on_click
 83    def _(_) -> None:
 84        gui_show_frame.value = True
 85        gui_location.value = 0.0
 86        gui_axis.value = "x"
 87        gui_num_points.value = 10_000
 88
 89        draw_frame()
 90        draw_points()
 91
 92    @gui_reset_scene_hold.on_hold
 93    def _(_) -> None:
 94        gui_show_frame.value = True
 95        gui_location.value = 0.0
 96        gui_axis.value = "x"
 97        gui_num_points.value = 10_000
 98
 99        draw_frame()
100        draw_points()
101
102    # Finally, let's add the initial frame + point cloud and just loop infinitely. :)
103    update_plane()
104    draw_frame()
105    draw_points()
106    while True:
107        time.sleep(1.0)
108
109
110if __name__ == "__main__":
111    main()