or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

3d-objects.mdadvanced-animations.mdanimation-system.mdboolean-operations.mdcoordinate-systems.mdindex.mdinteractive-controls.mdmathematical-objects.mdmatrix-visualization.mdprobability-stats.mdscene-framework.mdtext-and-latex.mdutilities-and-constants.mdvalue-tracking.mdvector-fields.md

interactive-controls.mddocs/

0

# Interactive Controls

1

2

ManimGL provides a comprehensive set of interactive controls that enable real-time user interaction with animations. These controls allow for dynamic parameter adjustment, UI widgets, and interactive scene manipulation, making ManimGL ideal for exploratory mathematical visualization and educational content.

3

4

## Capabilities

5

6

### Motion and Dragging

7

8

Enable any mobject to be draggable with mouse interactions, providing immediate visual feedback and manipulation.

9

10

```python { .api }

11

class MotionMobject(Mobject):

12

def __init__(self, mobject: Mobject, **kwargs):

13

"""

14

Make any mobject draggable with mouse interactions.

15

16

Parameters:

17

- mobject: Any Mobject to make draggable

18

"""

19

20

def mob_on_mouse_drag(self, mob: Mobject, event_data: dict[str, np.ndarray]) -> bool:

21

"""Handle mouse drag events for the wrapped mobject."""

22

```

23

24

### Button Controls

25

26

Convert any mobject into clickable buttons with custom callback functionality for interactive triggers.

27

28

```python { .api }

29

class Button(Mobject):

30

def __init__(self, mobject: Mobject, on_click: Callable[[Mobject]], **kwargs):

31

"""

32

Create a clickable button from any mobject.

33

34

Parameters:

35

- mobject: Any Mobject to make clickable

36

- on_click: Callback function that receives the mobject as argument

37

"""

38

39

def mob_on_mouse_press(self, mob: Mobject, event_data) -> bool:

40

"""Handle mouse press events and execute callback."""

41

```

42

43

### Toggle Controls

44

45

Boolean controls with visual feedback for binary state management and switching between options.

46

47

```python { .api }

48

class EnableDisableButton(ControlMobject):

49

def __init__(

50

self,

51

value: bool = True,

52

value_type: np.dtype = np.dtype(bool),

53

rect_kwargs: dict = {"width": 0.5, "height": 0.5, "fill_opacity": 1.0},

54

enable_color: ManimColor = GREEN,

55

disable_color: ManimColor = RED,

56

**kwargs

57

):

58

"""

59

Toggle button with color feedback for boolean values.

60

61

Parameters:

62

- value: Initial boolean state (default: True)

63

- rect_kwargs: Rectangle styling dictionary

64

- enable_color: Color when enabled (default: GREEN)

65

- disable_color: Color when disabled (default: RED)

66

"""

67

68

def toggle_value(self) -> None:

69

"""Toggle the button state between True and False."""

70

71

class Checkbox(ControlMobject):

72

def __init__(

73

self,

74

value: bool = True,

75

value_type: np.dtype = np.dtype(bool),

76

rect_kwargs: dict = {"width": 0.5, "height": 0.5, "fill_opacity": 0.0},

77

checkmark_kwargs: dict = {"stroke_color": GREEN, "stroke_width": 6},

78

cross_kwargs: dict = {"stroke_color": RED, "stroke_width": 6},

79

box_content_buff: float = SMALL_BUFF,

80

**kwargs

81

):

82

"""

83

Checkbox control with checkmark/cross visual indicators.

84

85

Parameters:

86

- value: Initial boolean state

87

- rect_kwargs: Checkbox box styling

88

- checkmark_kwargs: Checkmark appearance when True

89

- cross_kwargs: Cross appearance when False

90

- box_content_buff: Buffer around checkbox content

91

"""

92

93

def toggle_value(self) -> None:

94

"""Toggle between checked and unchecked states."""

95

96

def get_checkmark(self) -> VGroup:

97

"""Create checkmark symbol for True state."""

98

99

def get_cross(self) -> VGroup:

100

"""Create cross symbol for False state."""

101

```

102

103

### Numeric Input Controls

104

105

Slider controls for selecting numeric values within specified ranges with visual feedback and step control.

106

107

```python { .api }

108

class LinearNumberSlider(ControlMobject):

109

def __init__(

110

self,

111

value: float = 0,

112

value_type: type = np.float64,

113

min_value: float = -10.0,

114

max_value: float = 10.0,

115

step: float = 1.0,

116

rounded_rect_kwargs: dict = {

117

"height": 0.075, "width": 2, "corner_radius": 0.0375

118

},

119

circle_kwargs: dict = {

120

"radius": 0.1, "stroke_color": GREY_A,

121

"fill_color": GREY_A, "fill_opacity": 1.0

122

},

123

**kwargs

124

):

125

"""

126

Horizontal slider for numeric value selection.

127

128

Parameters:

129

- value: Initial numeric value

130

- value_type: Data type for the value

131

- min_value: Minimum allowed value

132

- max_value: Maximum allowed value

133

- step: Step size for value increments

134

- rounded_rect_kwargs: Slider bar appearance

135

- circle_kwargs: Slider handle appearance

136

"""

137

138

def slider_on_mouse_drag(self, mob, event_data: dict[str, np.ndarray]) -> bool:

139

"""Handle mouse drag events for slider interaction."""

140

141

def get_value_from_point(self, point: np.ndarray) -> float:

142

"""Convert screen position to slider value."""

143

```

144

145

### Color Selection

146

147

Advanced color picker with separate controls for red, green, blue, and alpha channels with live preview.

148

149

```python { .api }

150

class ColorSliders(ControlMobject):

151

def __init__(

152

self,

153

sliders_kwargs: dict = {},

154

rect_kwargs: dict = {"width": 2.0, "height": 0.5, "stroke_opacity": 1.0},

155

background_grid_kwargs: dict = {

156

"colors": [GREY_A, GREY_C], "single_square_len": 0.1

157

},

158

sliders_buff: float = MED_LARGE_BUFF,

159

default_rgb_value: int = 255,

160

default_a_value: int = 1,

161

**kwargs

162

):

163

"""

164

RGBA color picker with separate channel sliders.

165

166

Parameters:

167

- sliders_kwargs: Common settings for all sliders

168

- rect_kwargs: Color preview box styling

169

- background_grid_kwargs: Checkerboard background settings

170

- sliders_buff: Vertical spacing between sliders

171

- default_rgb_value: Initial RGB channel values (0-255)

172

- default_a_value: Initial alpha value (0-1)

173

"""

174

175

def set_value(self, r: float, g: float, b: float, a: float):

176

"""Set RGBA values directly."""

177

178

def get_value(self) -> np.ndarray:

179

"""Get current RGBA values as array."""

180

181

def get_picked_color(self) -> str:

182

"""Get current color as hex string."""

183

184

def get_picked_opacity(self) -> float:

185

"""Get current alpha value."""

186

187

def get_background(self) -> VGroup:

188

"""Create checkerboard background for transparency preview."""

189

```

190

191

### Text Input

192

193

Interactive text input fields with keyboard support and focus management for dynamic text content.

194

195

```python { .api }

196

class Textbox(ControlMobject):

197

def __init__(

198

self,

199

value: str = "",

200

value_type: np.dtype = np.dtype(object),

201

box_kwargs: dict = {

202

"width": 2.0, "height": 1.0,

203

"fill_color": WHITE, "fill_opacity": 1.0

204

},

205

text_kwargs: dict = {"color": BLUE},

206

text_buff: float = MED_SMALL_BUFF,

207

isInitiallyActive: bool = False,

208

active_color: ManimColor = BLUE,

209

deactive_color: ManimColor = RED,

210

**kwargs

211

):

212

"""

213

Interactive text input field with keyboard support.

214

215

Parameters:

216

- value: Initial text content

217

- box_kwargs: Text box appearance

218

- text_kwargs: Text styling

219

- text_buff: Padding inside text box

220

- isInitiallyActive: Whether textbox starts focused

221

- active_color: Border color when active

222

- deactive_color: Border color when inactive

223

"""

224

225

def update_text(self, value: str) -> None:

226

"""Update the displayed text content."""

227

228

def active_anim(self, isActive: bool) -> None:

229

"""Animate focus state changes."""

230

231

def box_on_mouse_press(self, mob, event_data) -> bool:

232

"""Handle mouse clicks to focus/unfocus."""

233

234

def on_key_press(self, mob: Mobject, event_data: dict[str, int]) -> bool | None:

235

"""Handle keyboard input events."""

236

```

237

238

### Control Organization

239

240

Container system for organizing and managing multiple interactive controls with collapsible panels.

241

242

```python { .api }

243

class ControlPanel(Group):

244

def __init__(

245

self,

246

*controls: ControlMobject,

247

panel_kwargs: dict = {

248

"width": FRAME_WIDTH/4, "height": MED_SMALL_BUFF + FRAME_HEIGHT,

249

"fill_color": GREY_C, "fill_opacity": 1.0, "stroke_width": 0.0

250

},

251

opener_kwargs: dict = {

252

"width": FRAME_WIDTH/8, "height": 0.5,

253

"fill_color": GREY_C, "fill_opacity": 1.0

254

},

255

opener_text_kwargs: dict = {"text": "Control Panel", "font_size": 20},

256

**kwargs

257

):

258

"""

259

Collapsible panel container for organizing controls.

260

261

Parameters:

262

- controls: Variable number of ControlMobject instances

263

- panel_kwargs: Panel background styling

264

- opener_kwargs: Panel handle styling

265

- opener_text_kwargs: Handle text appearance

266

"""

267

268

def add_controls(self, *new_controls: ControlMobject) -> None:

269

"""Add new controls to the panel."""

270

271

def remove_controls(self, *controls_to_remove: ControlMobject) -> None:

272

"""Remove controls from the panel."""

273

274

def open_panel(self):

275

"""Expand the control panel."""

276

277

def close_panel(self):

278

"""Collapse the control panel."""

279

280

def panel_opener_on_mouse_drag(self, mob, event_data: dict[str, np.ndarray]) -> bool:

281

"""Handle panel dragging for repositioning."""

282

283

def panel_on_mouse_scroll(self, mob, event_data: dict[str, np.ndarray]) -> bool:

284

"""Handle mouse scroll for content navigation."""

285

```

286

287

### Base Control Framework

288

289

Foundation classes for creating custom interactive controls with value tracking and animation integration.

290

291

```python { .api }

292

class ControlMobject(ValueTracker):

293

def __init__(self, value: float, *mobjects: Mobject, **kwargs):

294

"""

295

Abstract base class for interactive controls.

296

297

Parameters:

298

- value: Initial value for the control

299

- mobjects: Mobjects to include in the control

300

"""

301

302

def set_value(self, value: float):

303

"""Set the control's value programmatically."""

304

305

def assert_value(self, value):

306

"""Abstract method for value validation."""

307

308

def set_value_anim(self, value):

309

"""Abstract method for animated value updates."""

310

```

311

312

## Usage Examples

313

314

### Basic Interactive Animation

315

316

```python

317

from manimlib import *

318

319

class InteractiveDemo(Scene):

320

def setup(self):

321

# Create controls

322

self.slider = LinearNumberSlider(

323

value=1.0, min_value=0.5, max_value=3.0, step=0.1

324

)

325

self.color_picker = ColorSliders()

326

self.checkbox = Checkbox(value=True)

327

328

# Position controls

329

self.slider.to_edge(DOWN)

330

self.color_picker.to_edge(RIGHT)

331

self.checkbox.to_edge(UP)

332

333

self.add(self.slider, self.color_picker, self.checkbox)

334

335

def construct(self):

336

# Create reactive circle

337

circle = Circle(radius=1, color=BLUE)

338

339

# Add updater that responds to controls

340

def circle_updater(c):

341

# Update radius from slider

342

new_radius = self.slider.get_value()

343

c.set_width(2 * new_radius)

344

345

# Update color from color picker

346

if self.checkbox.get_value():

347

c.set_fill(

348

color=self.color_picker.get_picked_color(),

349

opacity=self.color_picker.get_picked_opacity()

350

)

351

else:

352

c.set_fill(BLUE, opacity=1)

353

354

circle.add_updater(circle_updater)

355

self.add(circle)

356

357

# Make circle draggable

358

self.add(MotionMobject(circle))

359

360

self.wait(10) # Interactive exploration time

361

```

362

363

### Button-Triggered Animations

364

365

```python

366

class ButtonDemo(Scene):

367

def setup(self):

368

self.circles = VGroup()

369

370

# Create buttons

371

add_button = Button(

372

Text("Add Circle", font_size=24).set_fill(WHITE).add_background_rectangle(),

373

on_click=self.add_circle

374

)

375

376

clear_button = Button(

377

Text("Clear", font_size=24).set_fill(WHITE).add_background_rectangle(),

378

on_click=self.clear_circles

379

)

380

381

# Position buttons

382

buttons = VGroup(add_button, clear_button)

383

buttons.arrange(RIGHT, buff=1)

384

buttons.to_edge(DOWN)

385

386

self.add(buttons)

387

388

def add_circle(self, button):

389

"""Callback to add a new circle"""

390

circle = Circle(radius=0.3, color=random_color())

391

circle.move_to(3 * np.random.random(3) - 1.5)

392

self.circles.add(circle)

393

self.add(circle)

394

395

def clear_circles(self, button):

396

"""Callback to clear all circles"""

397

self.remove(self.circles)

398

self.circles = VGroup()

399

400

def construct(self):

401

self.wait(10)

402

```

403

404

### Control Panel Organization

405

406

```python

407

class ControlPanelDemo(Scene):

408

def setup(self):

409

# Create individual controls

410

amplitude_slider = LinearNumberSlider(

411

value=1.0, min_value=0.1, max_value=2.0, step=0.1

412

)

413

frequency_slider = LinearNumberSlider(

414

value=1.0, min_value=0.1, max_value=5.0, step=0.1

415

)

416

color_controls = ColorSliders()

417

show_axes = Checkbox(value=True)

418

419

# Organize in panel with labels

420

panel = ControlPanel(

421

Text("Amplitude", font_size=20), amplitude_slider,

422

Text("Frequency", font_size=20), frequency_slider,

423

Text("Wave Color", font_size=20), color_controls,

424

Text("Show Axes", font_size=20), show_axes

425

)

426

427

panel.to_edge(LEFT)

428

self.add(panel)

429

430

# Store controls for access

431

self.amplitude_slider = amplitude_slider

432

self.frequency_slider = frequency_slider

433

self.color_controls = color_controls

434

self.show_axes = show_axes

435

436

def construct(self):

437

# Create responsive function plot

438

axes = Axes(x_range=[-3, 3], y_range=[-2, 2])

439

440

def get_wave():

441

return axes.plot(

442

lambda x: self.amplitude_slider.get_value() * np.sin(

443

self.frequency_slider.get_value() * x

444

),

445

color=self.color_controls.get_picked_color()

446

)

447

448

wave = get_wave()

449

450

def wave_updater(w):

451

new_wave = get_wave()

452

w.become(new_wave)

453

454

def axes_updater(a):

455

a.set_opacity(1 if self.show_axes.get_value() else 0)

456

457

wave.add_updater(wave_updater)

458

axes.add_updater(axes_updater)

459

460

self.add(axes, wave)

461

self.wait(15)

462

```

463

464

## Interactive Scene Framework

465

466

```python { .api }

467

class InteractiveScene(Scene):

468

"""

469

Enhanced scene class with built-in selection and manipulation tools.

470

471

Features:

472

- Object selection with Ctrl+click/drag

473

- Grabbing modes (G/H/V keys for general/horizontal/vertical)

474

- Resizing with T key

475

- Copy/paste operations (Cmd+C/V/X)

476

- Color palette toggle

477

- Comprehensive keyboard shortcuts

478

"""

479

480

def add_to_selection(self, *mobjects):

481

"""Add mobjects to current selection."""

482

483

def clear_selection(self):

484

"""Clear current selection."""

485

486

def toggle_from_selection(self, mobject):

487

"""Toggle mobject in/out of selection."""

488

489

def copy_selection(self):

490

"""Copy selected mobjects to clipboard."""

491

492

def paste_selection(self):

493

"""Paste mobjects from clipboard."""

494

495

def delete_selection(self):

496

"""Delete currently selected mobjects."""

497

```

498

499

The interactive controls system in ManimGL provides a complete framework for building dynamic, responsive mathematical animations with real-time user interaction and parameter adjustment capabilities.