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

value-tracking.mddocs/

0

# Value Tracking

1

2

ManimGL's value tracking system provides powerful tools for managing numeric parameters that change over time during animations. Value trackers are invisible mobjects that store numeric data and integrate seamlessly with the animation system, enabling complex parameter-dependent animations and interactive controls.

3

4

## Capabilities

5

6

### Basic Value Tracking

7

8

Store and animate numeric values that can drive parameter-dependent animations and link multiple objects to shared data sources.

9

10

```python { .api }

11

class ValueTracker(Mobject):

12

value_type: type = np.float64

13

14

def __init__(self, value: float | complex | np.ndarray = 0, **kwargs):

15

"""

16

Initialize a value tracker with a numeric value.

17

18

Parameters:

19

- value: Initial numeric value (scalar, complex, or array)

20

- kwargs: Additional Mobject keyword arguments

21

"""

22

23

def get_value(self) -> float | complex | np.ndarray:

24

"""

25

Retrieve the current tracked value.

26

27

Returns:

28

Current value (scalar if single value, array if multiple values)

29

"""

30

31

def set_value(self, value: float | complex | np.ndarray) -> Self:

32

"""

33

Update the tracked value.

34

35

Parameters:

36

- value: New numeric value to store

37

38

Returns:

39

Self for method chaining

40

"""

41

42

def increment_value(self, d_value: float | complex) -> None:

43

"""

44

Add the specified amount to the current value.

45

46

Parameters:

47

- d_value: Amount to add to current value

48

"""

49

50

def init_uniforms(self) -> None:

51

"""Initialize internal uniform data structure for GPU integration."""

52

```

53

54

### Exponential Value Tracking

55

56

Specialized tracker for exponential interpolation, storing values in logarithmic space for natural exponential animation behavior.

57

58

```python { .api }

59

class ExponentialValueTracker(ValueTracker):

60

def __init__(self, value: float | complex = 1, **kwargs):

61

"""

62

Initialize tracker for exponential value changes.

63

64

Parameters:

65

- value: Initial value (stored as log internally)

66

- kwargs: Additional ValueTracker arguments

67

"""

68

69

def get_value(self) -> float | complex:

70

"""

71

Get the exponential of the stored value.

72

73

Returns:

74

np.exp(internal_value) - the actual exponential value

75

"""

76

77

def set_value(self, value: float | complex):

78

"""

79

Set value by storing its logarithm internally.

80

81

Parameters:

82

- value: Actual value to represent (stored as log)

83

"""

84

```

85

86

### Complex Number Tracking

87

88

Optimized tracker for complex number values with high-precision complex number operations.

89

90

```python { .api }

91

class ComplexValueTracker(ValueTracker):

92

value_type: type = np.complex128

93

94

def __init__(self, value: complex = 0+0j, **kwargs):

95

"""

96

Initialize tracker for complex number values.

97

98

Parameters:

99

- value: Initial complex number value

100

- kwargs: Additional ValueTracker arguments

101

"""

102

```

103

104

## Usage Examples

105

106

### Basic Parameter Animation

107

108

```python

109

from manimlib import *

110

111

class BasicValueTracking(Scene):

112

def construct(self):

113

# Create a value tracker for controlling opacity

114

opacity_tracker = ValueTracker(0)

115

116

# Create objects that respond to the tracker

117

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

118

square = Square(side_length=3, color=RED, fill_opacity=1)

119

120

# Link objects to the tracker value

121

circle.add_updater(

122

lambda c: c.set_fill_opacity(opacity_tracker.get_value())

123

)

124

square.add_updater(

125

lambda s: s.set_fill_opacity(1 - opacity_tracker.get_value())

126

)

127

128

self.add(circle, square)

129

130

# Animate the tracked value

131

self.play(opacity_tracker.animate.set_value(1), run_time=3)

132

self.play(opacity_tracker.animate.set_value(0.5), run_time=2)

133

self.play(opacity_tracker.animate.set_value(0), run_time=3)

134

```

135

136

### Function Plotting with Value Tracking

137

138

```python

139

class DynamicFunctionPlot(Scene):

140

def construct(self):

141

# Create coordinate system

142

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

143

self.add(axes)

144

145

# Create value trackers for function parameters

146

amplitude = ValueTracker(1)

147

frequency = ValueTracker(1)

148

phase = ValueTracker(0)

149

150

# Create function that depends on trackers

151

def get_sine_graph():

152

return axes.plot(

153

lambda x: (

154

amplitude.get_value() *

155

np.sin(frequency.get_value() * x + phase.get_value())

156

),

157

color=YELLOW

158

)

159

160

# Create initial graph

161

graph = get_sine_graph()

162

163

# Add updater to redraw graph when parameters change

164

graph.add_updater(lambda g: g.become(get_sine_graph()))

165

166

self.add(graph)

167

168

# Animate parameters

169

self.play(amplitude.animate.set_value(1.5), run_time=2)

170

self.play(frequency.animate.set_value(2), run_time=2)

171

self.play(phase.animate.set_value(PI/2), run_time=2)

172

173

# Multiple parameters simultaneously

174

self.play(

175

amplitude.animate.set_value(0.5),

176

frequency.animate.set_value(3),

177

phase.animate.set_value(0),

178

run_time=3

179

)

180

```

181

182

### Exponential Growth Animation

183

184

```python

185

class ExponentialAnimation(Scene):

186

def construct(self):

187

# Create exponential value tracker for smooth exponential growth

188

scale_tracker = ExponentialValueTracker(1)

189

190

# Create object that will grow exponentially

191

circle = Circle(radius=0.5, color=BLUE, fill_opacity=0.7)

192

193

# Link circle size to exponential tracker

194

def update_circle(c):

195

scale_factor = scale_tracker.get_value()

196

c.set_width(scale_factor)

197

c.set_height(scale_factor)

198

# Color intensity based on size

199

opacity = min(1, scale_factor / 5)

200

c.set_fill_opacity(opacity)

201

202

circle.add_updater(update_circle)

203

self.add(circle)

204

205

# Animate exponential growth (linear interpolation in log space)

206

self.play(scale_tracker.animate.set_value(10), run_time=4)

207

self.wait()

208

209

# Exponential decay

210

self.play(scale_tracker.animate.set_value(0.1), run_time=3)

211

```

212

213

### Complex Parameter Control

214

215

```python

216

class ComplexValueDemo(Scene):

217

def construct(self):

218

# Use complex tracker for rotation and scaling combined

219

complex_tracker = ComplexValueTracker(1+0j)

220

221

# Create shape to transform

222

arrow = Arrow(ORIGIN, RIGHT, color=RED, buff=0)

223

224

# Transform arrow based on complex number

225

def update_arrow(a):

226

complex_val = complex_tracker.get_value()

227

# Complex multiplication = rotation + scaling

228

magnitude = abs(complex_val)

229

angle = np.angle(complex_val)

230

231

a.become(Arrow(ORIGIN, RIGHT, buff=0, color=RED))

232

a.scale(magnitude)

233

a.rotate(angle)

234

235

arrow.add_updater(update_arrow)

236

self.add(arrow)

237

238

# Animate in complex plane

239

self.play(

240

complex_tracker.animate.set_value(2 * np.exp(1j * PI/4)),

241

run_time=2

242

)

243

self.play(

244

complex_tracker.animate.set_value(3 * np.exp(1j * PI)),

245

run_time=2

246

)

247

self.play(

248

complex_tracker.animate.set_value(0.5 * np.exp(1j * 2*PI)),

249

run_time=3

250

)

251

```

252

253

### Multi-Parameter Coordination

254

255

```python

256

class CoordinatedParameters(Scene):

257

def construct(self):

258

# Create multiple coordinated trackers

259

x_pos = ValueTracker(-3)

260

y_pos = ValueTracker(0)

261

size = ValueTracker(0.5)

262

hue = ValueTracker(0)

263

264

# Create object that depends on all parameters

265

circle = Circle(radius=0.5, fill_opacity=0.8)

266

267

def update_circle(c):

268

# Position

269

c.move_to([x_pos.get_value(), y_pos.get_value(), 0])

270

271

# Size

272

c.set_width(2 * size.get_value())

273

c.set_height(2 * size.get_value())

274

275

# Color based on hue value

276

import colorsys

277

rgb = colorsys.hsv_to_rgb(hue.get_value(), 1, 1)

278

c.set_fill(rgb_to_color(rgb))

279

280

circle.add_updater(update_circle)

281

self.add(circle)

282

283

# Coordinate multiple parameter changes

284

self.play(

285

x_pos.animate.set_value(3),

286

y_pos.animate.set_value(2),

287

size.animate.set_value(1.5),

288

hue.animate.set_value(0.3),

289

run_time=4

290

)

291

292

# Create circular motion with changing properties

293

self.play(

294

x_pos.animate.set_value(-3),

295

y_pos.animate.set_value(-2),

296

size.animate.set_value(0.3),

297

hue.animate.set_value(0.8),

298

run_time=3

299

)

300

```

301

302

### Interactive Parameter Control

303

304

```python

305

from manimlib.mobject.interactive import LinearNumberSlider

306

307

class InteractiveValueTracking(Scene):

308

def setup(self):

309

# Create sliders that are themselves value trackers

310

self.amplitude_slider = LinearNumberSlider(

311

value=1, min_value=0, max_value=3, step=0.1

312

)

313

self.frequency_slider = LinearNumberSlider(

314

value=1, min_value=0.1, max_value=5, step=0.1

315

)

316

317

# Position sliders

318

self.amplitude_slider.to_edge(DOWN).shift(UP * 0.5)

319

self.frequency_slider.to_edge(DOWN)

320

321

self.add(self.amplitude_slider, self.frequency_slider)

322

323

def construct(self):

324

# Create responsive visualization

325

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

326

327

def get_wave():

328

return axes.plot(

329

lambda x: (

330

self.amplitude_slider.get_value() *

331

np.sin(self.frequency_slider.get_value() * x)

332

),

333

color=YELLOW

334

)

335

336

wave = get_wave()

337

wave.add_updater(lambda w: w.become(get_wave()))

338

339

self.add(axes, wave)

340

341

# Create labels that show current values

342

amplitude_label = Text("Amplitude: 1.0", font_size=24)

343

frequency_label = Text("Frequency: 1.0", font_size=24)

344

345

amplitude_label.to_edge(UP).shift(DOWN * 0.5)

346

frequency_label.to_edge(UP)

347

348

def update_amp_label(label):

349

val = self.amplitude_slider.get_value()

350

label.become(Text(f"Amplitude: {val:.1f}", font_size=24))

351

label.to_edge(UP).shift(DOWN * 0.5)

352

353

def update_freq_label(label):

354

val = self.frequency_slider.get_value()

355

label.become(Text(f"Frequency: {val:.1f}", font_size=24))

356

label.to_edge(UP)

357

358

amplitude_label.add_updater(update_amp_label)

359

frequency_label.add_updater(update_freq_label)

360

361

self.add(amplitude_label, frequency_label)

362

363

# Interactive exploration time

364

self.wait(10)

365

```

366

367

## Integration with Animation System

368

369

### Chaining Operations

370

371

```python

372

# Value trackers support method chaining

373

tracker = ValueTracker(0)

374

tracker.set_value(5).increment_value(2) # Final value: 7

375

376

# Animation chaining

377

self.play(

378

tracker.animate.set_value(10),

379

other_object.animate.shift(UP)

380

)

381

```

382

383

### Updater Patterns

384

385

```python

386

# Time-based updaters (receive dt parameter)

387

def time_updater(mob, dt):

388

mob.rotate(dt * tracker.get_value())

389

390

mob.add_updater(time_updater)

391

392

# Non-time-based updaters (called every frame)

393

def position_updater(mob):

394

mob.move_to([tracker.get_value(), 0, 0])

395

396

mob.add_updater(position_updater, call_updater=True)

397

```

398

399

### Advanced Animation Patterns

400

401

```python

402

# Multiple trackers with different rate functions

403

self.play(

404

tracker1.animate.set_value(5).set_rate_func(smooth),

405

tracker2.animate.set_value(10).set_rate_func(linear),

406

tracker3.animate.set_value(2).set_rate_func(there_and_back),

407

run_time=3

408

)

409

410

# Staggered animations

411

self.play(

412

AnimationGroup(

413

tracker1.animate.set_value(5),

414

tracker2.animate.set_value(3),

415

tracker3.animate.set_value(8),

416

lag_ratio=0.3

417

),

418

run_time=4

419

)

420

```

421

422

## Technical Implementation

423

424

### Data Storage Architecture

425

426

Value trackers store data in `self.uniforms["value"]` as numpy arrays, enabling:

427

- GPU shader integration for advanced rendering

428

- Consistent handling of scalar and array values

429

- Efficient memory management and updates

430

431

### Animation Integration

432

433

- Inherits full animation capabilities from Mobject base class

434

- Compatible with `.animate` syntax for smooth transitions

435

- Supports all interpolation and transformation methods

436

- Integrates with rate functions and animation timing

437

438

### Performance Considerations

439

440

- Value trackers are lightweight and efficient for real-time updates

441

- Updater functions are called every frame - keep them optimized

442

- Use `clear_updaters()` when no longer needed to prevent memory leaks

443

- For complex calculations, consider caching results when tracker values haven't changed

444

445

The value tracking system provides the foundation for sophisticated parameter-dependent animations in ManimGL, enabling smooth interpolation of any numeric parameter while maintaining full integration with the animation and rendering pipeline.