Mesh click events¶
Click on meshes to select them.
This example demonstrates how to make 3D objects interactive using click events. Each mesh in the grid responds to mouse clicks, cycling through different states (gray box → colored box → colored sphere).
Key concepts:
Click handlers attached to meshes and icospheres
Scene objects created with
viser.SceneApi.add_box()
andviser.SceneApi.add_icosphere()
Dynamic object replacement by using the same
name
parameterGUI state updates from 3D interactions (displaying clicked mesh coordinates)
This pattern is useful for building interactive 3D applications where users can select, modify, or inspect scene objects by clicking on them. The click coordinates are automatically calculated by the 3D engine and passed to your callback functions.
Source: examples/03_interaction/00_click_meshes.py

Code¶
1import time
2
3import matplotlib
4
5import viser
6
7
8def main() -> None:
9 grid_shape = (4, 5)
10 server = viser.ViserServer()
11
12 with server.gui.add_folder("Last clicked"):
13 x_value = server.gui.add_number(
14 label="x",
15 initial_value=0,
16 disabled=True,
17 hint="x coordinate of the last clicked mesh",
18 )
19 y_value = server.gui.add_number(
20 label="y",
21 initial_value=0,
22 disabled=True,
23 hint="y coordinate of the last clicked mesh",
24 )
25
26 def add_swappable_mesh(i: int, j: int) -> None:
27
28 colormap = matplotlib.colormaps["tab20"]
29
30 def create_mesh(counter: int) -> None:
31 if counter == 0:
32 color = (0.8, 0.8, 0.8)
33 else:
34 index = (i * grid_shape[1] + j) / (grid_shape[0] * grid_shape[1])
35 color = colormap(index)[:3]
36
37 if counter in (0, 1):
38 handle = server.scene.add_box(
39 name=f"/sphere_{i}_{j}",
40 position=(i, j, 0.0),
41 color=color,
42 dimensions=(0.5, 0.5, 0.5),
43 )
44 else:
45 handle = server.scene.add_icosphere(
46 name=f"/sphere_{i}_{j}",
47 radius=0.4,
48 color=color,
49 position=(i, j, 0.0),
50 )
51
52 @handle.on_click
53 def _(_) -> None:
54 x_value.value = i
55 y_value.value = j
56
57 # The new mesh will replace the old one because the names
58 # /sphere_{i}_{j} are the same.
59 create_mesh((counter + 1) % 3)
60
61 create_mesh(0)
62
63 for i in range(grid_shape[0]):
64 for j in range(grid_shape[1]):
65 add_swappable_mesh(i, j)
66
67 while True:
68 time.sleep(10.0)
69
70
71if __name__ == "__main__":
72 main()