CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-manimgl

Animation engine for explanatory math videos with programmatic mathematical visualization capabilities

Pending
Overview
Eval results
Files

interactive-controls.mddocs/

Interactive Controls

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.

Capabilities

Motion and Dragging

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

class MotionMobject(Mobject):
    def __init__(self, mobject: Mobject, **kwargs):
        """
        Make any mobject draggable with mouse interactions.
        
        Parameters:
        - mobject: Any Mobject to make draggable
        """
    
    def mob_on_mouse_drag(self, mob: Mobject, event_data: dict[str, np.ndarray]) -> bool:
        """Handle mouse drag events for the wrapped mobject."""

Button Controls

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

class Button(Mobject):
    def __init__(self, mobject: Mobject, on_click: Callable[[Mobject]], **kwargs):
        """
        Create a clickable button from any mobject.
        
        Parameters:
        - mobject: Any Mobject to make clickable
        - on_click: Callback function that receives the mobject as argument
        """
    
    def mob_on_mouse_press(self, mob: Mobject, event_data) -> bool:
        """Handle mouse press events and execute callback."""

Toggle Controls

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

class EnableDisableButton(ControlMobject):
    def __init__(
        self,
        value: bool = True,
        value_type: np.dtype = np.dtype(bool),
        rect_kwargs: dict = {"width": 0.5, "height": 0.5, "fill_opacity": 1.0},
        enable_color: ManimColor = GREEN,
        disable_color: ManimColor = RED,
        **kwargs
    ):
        """
        Toggle button with color feedback for boolean values.
        
        Parameters:
        - value: Initial boolean state (default: True)
        - rect_kwargs: Rectangle styling dictionary
        - enable_color: Color when enabled (default: GREEN)
        - disable_color: Color when disabled (default: RED)
        """
    
    def toggle_value(self) -> None:
        """Toggle the button state between True and False."""

class Checkbox(ControlMobject):
    def __init__(
        self,
        value: bool = True,
        value_type: np.dtype = np.dtype(bool),
        rect_kwargs: dict = {"width": 0.5, "height": 0.5, "fill_opacity": 0.0},
        checkmark_kwargs: dict = {"stroke_color": GREEN, "stroke_width": 6},
        cross_kwargs: dict = {"stroke_color": RED, "stroke_width": 6},
        box_content_buff: float = SMALL_BUFF,
        **kwargs
    ):
        """
        Checkbox control with checkmark/cross visual indicators.
        
        Parameters:
        - value: Initial boolean state
        - rect_kwargs: Checkbox box styling
        - checkmark_kwargs: Checkmark appearance when True
        - cross_kwargs: Cross appearance when False
        - box_content_buff: Buffer around checkbox content
        """
    
    def toggle_value(self) -> None:
        """Toggle between checked and unchecked states."""
    
    def get_checkmark(self) -> VGroup:
        """Create checkmark symbol for True state."""
    
    def get_cross(self) -> VGroup:
        """Create cross symbol for False state."""

Numeric Input Controls

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

class LinearNumberSlider(ControlMobject):
    def __init__(
        self,
        value: float = 0,
        value_type: type = np.float64,
        min_value: float = -10.0,
        max_value: float = 10.0,
        step: float = 1.0,
        rounded_rect_kwargs: dict = {
            "height": 0.075, "width": 2, "corner_radius": 0.0375
        },
        circle_kwargs: dict = {
            "radius": 0.1, "stroke_color": GREY_A, 
            "fill_color": GREY_A, "fill_opacity": 1.0
        },
        **kwargs
    ):
        """
        Horizontal slider for numeric value selection.
        
        Parameters:
        - value: Initial numeric value
        - value_type: Data type for the value
        - min_value: Minimum allowed value
        - max_value: Maximum allowed value
        - step: Step size for value increments
        - rounded_rect_kwargs: Slider bar appearance
        - circle_kwargs: Slider handle appearance
        """
    
    def slider_on_mouse_drag(self, mob, event_data: dict[str, np.ndarray]) -> bool:
        """Handle mouse drag events for slider interaction."""
    
    def get_value_from_point(self, point: np.ndarray) -> float:
        """Convert screen position to slider value."""

Color Selection

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

class ColorSliders(ControlMobject):
    def __init__(
        self,
        sliders_kwargs: dict = {},
        rect_kwargs: dict = {"width": 2.0, "height": 0.5, "stroke_opacity": 1.0},
        background_grid_kwargs: dict = {
            "colors": [GREY_A, GREY_C], "single_square_len": 0.1
        },
        sliders_buff: float = MED_LARGE_BUFF,
        default_rgb_value: int = 255,
        default_a_value: int = 1,
        **kwargs
    ):
        """
        RGBA color picker with separate channel sliders.
        
        Parameters:
        - sliders_kwargs: Common settings for all sliders
        - rect_kwargs: Color preview box styling
        - background_grid_kwargs: Checkerboard background settings
        - sliders_buff: Vertical spacing between sliders
        - default_rgb_value: Initial RGB channel values (0-255)
        - default_a_value: Initial alpha value (0-1)
        """
    
    def set_value(self, r: float, g: float, b: float, a: float):
        """Set RGBA values directly."""
    
    def get_value(self) -> np.ndarray:
        """Get current RGBA values as array."""
    
    def get_picked_color(self) -> str:
        """Get current color as hex string."""
    
    def get_picked_opacity(self) -> float:
        """Get current alpha value."""
    
    def get_background(self) -> VGroup:
        """Create checkerboard background for transparency preview."""

Text Input

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

class Textbox(ControlMobject):
    def __init__(
        self,
        value: str = "",
        value_type: np.dtype = np.dtype(object),
        box_kwargs: dict = {
            "width": 2.0, "height": 1.0, 
            "fill_color": WHITE, "fill_opacity": 1.0
        },
        text_kwargs: dict = {"color": BLUE},
        text_buff: float = MED_SMALL_BUFF,
        isInitiallyActive: bool = False,
        active_color: ManimColor = BLUE,
        deactive_color: ManimColor = RED,
        **kwargs
    ):
        """
        Interactive text input field with keyboard support.
        
        Parameters:
        - value: Initial text content
        - box_kwargs: Text box appearance
        - text_kwargs: Text styling
        - text_buff: Padding inside text box
        - isInitiallyActive: Whether textbox starts focused
        - active_color: Border color when active
        - deactive_color: Border color when inactive
        """
    
    def update_text(self, value: str) -> None:
        """Update the displayed text content."""
    
    def active_anim(self, isActive: bool) -> None:
        """Animate focus state changes."""
    
    def box_on_mouse_press(self, mob, event_data) -> bool:
        """Handle mouse clicks to focus/unfocus."""
    
    def on_key_press(self, mob: Mobject, event_data: dict[str, int]) -> bool | None:
        """Handle keyboard input events."""

Control Organization

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

class ControlPanel(Group):
    def __init__(
        self,
        *controls: ControlMobject,
        panel_kwargs: dict = {
            "width": FRAME_WIDTH/4, "height": MED_SMALL_BUFF + FRAME_HEIGHT,
            "fill_color": GREY_C, "fill_opacity": 1.0, "stroke_width": 0.0
        },
        opener_kwargs: dict = {
            "width": FRAME_WIDTH/8, "height": 0.5,
            "fill_color": GREY_C, "fill_opacity": 1.0
        },
        opener_text_kwargs: dict = {"text": "Control Panel", "font_size": 20},
        **kwargs
    ):
        """
        Collapsible panel container for organizing controls.
        
        Parameters:
        - controls: Variable number of ControlMobject instances
        - panel_kwargs: Panel background styling
        - opener_kwargs: Panel handle styling
        - opener_text_kwargs: Handle text appearance
        """
    
    def add_controls(self, *new_controls: ControlMobject) -> None:
        """Add new controls to the panel."""
    
    def remove_controls(self, *controls_to_remove: ControlMobject) -> None:
        """Remove controls from the panel."""
    
    def open_panel(self):
        """Expand the control panel."""
    
    def close_panel(self):
        """Collapse the control panel."""
    
    def panel_opener_on_mouse_drag(self, mob, event_data: dict[str, np.ndarray]) -> bool:
        """Handle panel dragging for repositioning."""
    
    def panel_on_mouse_scroll(self, mob, event_data: dict[str, np.ndarray]) -> bool:
        """Handle mouse scroll for content navigation."""

Base Control Framework

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

class ControlMobject(ValueTracker):
    def __init__(self, value: float, *mobjects: Mobject, **kwargs):
        """
        Abstract base class for interactive controls.
        
        Parameters:
        - value: Initial value for the control
        - mobjects: Mobjects to include in the control
        """
    
    def set_value(self, value: float):
        """Set the control's value programmatically."""
    
    def assert_value(self, value):
        """Abstract method for value validation."""
    
    def set_value_anim(self, value):
        """Abstract method for animated value updates."""

Usage Examples

Basic Interactive Animation

from manimlib import *

class InteractiveDemo(Scene):
    def setup(self):
        # Create controls
        self.slider = LinearNumberSlider(
            value=1.0, min_value=0.5, max_value=3.0, step=0.1
        )
        self.color_picker = ColorSliders()
        self.checkbox = Checkbox(value=True)
        
        # Position controls
        self.slider.to_edge(DOWN)
        self.color_picker.to_edge(RIGHT)
        self.checkbox.to_edge(UP)
        
        self.add(self.slider, self.color_picker, self.checkbox)
    
    def construct(self):
        # Create reactive circle
        circle = Circle(radius=1, color=BLUE)
        
        # Add updater that responds to controls
        def circle_updater(c):
            # Update radius from slider
            new_radius = self.slider.get_value()
            c.set_width(2 * new_radius)
            
            # Update color from color picker
            if self.checkbox.get_value():
                c.set_fill(
                    color=self.color_picker.get_picked_color(),
                    opacity=self.color_picker.get_picked_opacity()
                )
            else:
                c.set_fill(BLUE, opacity=1)
        
        circle.add_updater(circle_updater)
        self.add(circle)
        
        # Make circle draggable
        self.add(MotionMobject(circle))
        
        self.wait(10)  # Interactive exploration time

Button-Triggered Animations

class ButtonDemo(Scene):
    def setup(self):
        self.circles = VGroup()
        
        # Create buttons
        add_button = Button(
            Text("Add Circle", font_size=24).set_fill(WHITE).add_background_rectangle(),
            on_click=self.add_circle
        )
        
        clear_button = Button(
            Text("Clear", font_size=24).set_fill(WHITE).add_background_rectangle(),
            on_click=self.clear_circles
        )
        
        # Position buttons
        buttons = VGroup(add_button, clear_button)
        buttons.arrange(RIGHT, buff=1)
        buttons.to_edge(DOWN)
        
        self.add(buttons)
    
    def add_circle(self, button):
        """Callback to add a new circle"""
        circle = Circle(radius=0.3, color=random_color())
        circle.move_to(3 * np.random.random(3) - 1.5)
        self.circles.add(circle)
        self.add(circle)
    
    def clear_circles(self, button):
        """Callback to clear all circles"""
        self.remove(self.circles)
        self.circles = VGroup()
    
    def construct(self):
        self.wait(10)

Control Panel Organization

class ControlPanelDemo(Scene):
    def setup(self):
        # Create individual controls
        amplitude_slider = LinearNumberSlider(
            value=1.0, min_value=0.1, max_value=2.0, step=0.1
        )
        frequency_slider = LinearNumberSlider(
            value=1.0, min_value=0.1, max_value=5.0, step=0.1
        )
        color_controls = ColorSliders()
        show_axes = Checkbox(value=True)
        
        # Organize in panel with labels
        panel = ControlPanel(
            Text("Amplitude", font_size=20), amplitude_slider,
            Text("Frequency", font_size=20), frequency_slider,
            Text("Wave Color", font_size=20), color_controls,
            Text("Show Axes", font_size=20), show_axes
        )
        
        panel.to_edge(LEFT)
        self.add(panel)
        
        # Store controls for access
        self.amplitude_slider = amplitude_slider
        self.frequency_slider = frequency_slider
        self.color_controls = color_controls
        self.show_axes = show_axes
    
    def construct(self):
        # Create responsive function plot
        axes = Axes(x_range=[-3, 3], y_range=[-2, 2])
        
        def get_wave():
            return axes.plot(
                lambda x: self.amplitude_slider.get_value() * np.sin(
                    self.frequency_slider.get_value() * x
                ),
                color=self.color_controls.get_picked_color()
            )
        
        wave = get_wave()
        
        def wave_updater(w):
            new_wave = get_wave()
            w.become(new_wave)
        
        def axes_updater(a):
            a.set_opacity(1 if self.show_axes.get_value() else 0)
        
        wave.add_updater(wave_updater)
        axes.add_updater(axes_updater)
        
        self.add(axes, wave)
        self.wait(15)

Interactive Scene Framework

class InteractiveScene(Scene):
    """
    Enhanced scene class with built-in selection and manipulation tools.
    
    Features:
    - Object selection with Ctrl+click/drag
    - Grabbing modes (G/H/V keys for general/horizontal/vertical)
    - Resizing with T key
    - Copy/paste operations (Cmd+C/V/X)
    - Color palette toggle
    - Comprehensive keyboard shortcuts
    """
    
    def add_to_selection(self, *mobjects):
        """Add mobjects to current selection."""
    
    def clear_selection(self):
        """Clear current selection."""
    
    def toggle_from_selection(self, mobject):
        """Toggle mobject in/out of selection."""
    
    def copy_selection(self):
        """Copy selected mobjects to clipboard."""
    
    def paste_selection(self):
        """Paste mobjects from clipboard."""
    
    def delete_selection(self):
        """Delete currently selected mobjects."""

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.

Install with Tessl CLI

npx tessl i tessl/pypi-manimgl

docs

3d-objects.md

advanced-animations.md

animation-system.md

boolean-operations.md

coordinate-systems.md

index.md

interactive-controls.md

mathematical-objects.md

matrix-visualization.md

probability-stats.md

scene-framework.md

text-and-latex.md

utilities-and-constants.md

value-tracking.md

vector-fields.md

tile.json