Animation Manager - griffingilreath/Punch-Card-Project GitHub Wiki
Animation Manager (Beta)
This document explains the technical implementation of the Animation Manager component in the Punch Card Project. Note that this feature is currently in beta with some known issues.
Overview
The Animation Manager provides a centralized system for coordinating animations across both the GUI and hardware components. It replaces the previous approach of scattered animation logic with a consistent API and synchronization mechanism.
Key Features
- Centralized Animation Logic: Single point of control for all animations
- Consistent API: Unified interface for creating and managing animations
- Synchronized Animations: Coordinate GUI and hardware animations
- Complex Animation Sequences: Support for multi-stage animation sequences
- Event-Driven Architecture: React to animation events and state changes
Current Limitations (Beta Status)
The Animation Manager is currently in beta with several known limitations:
- Occasional timing issues with complex animation sequences
- Memory usage increases with animation complexity
- Some animations fail to complete properly when interrupted
- Performance overhead for simple animations
- API may change as we gather more feedback
Implementation
Core Components
The Animation Manager is built around these key components:
- AnimationManager Class: Central class that coordinates all animations
- Animation Class: Base class for different animation types
- AnimationSequence Class: Container for multi-stage animations
- AnimationEvent System: Event handling for animation states
AnimationManager Class
The AnimationManager class provides a simple interface for creating and controlling animations:
class AnimationManager:
def __init__(self):
self.animations = {}
self.active_animations = set()
self.event_handlers = {}
def create_animation(self, animation_type, **kwargs):
"""Create a new animation of the specified type"""
animation = animation_type(**kwargs)
self.animations[animation.id] = animation
return animation
def start_animation(self, animation_id):
"""Start an animation by ID"""
if animation_id in self.animations:
animation = self.animations[animation_id]
animation.start()
self.active_animations.add(animation_id)
self.trigger_event(AnimationEvent.STARTED, animation)
def stop_animation(self, animation_id):
"""Stop an animation by ID"""
if animation_id in self.active_animations:
animation = self.animations[animation_id]
animation.stop()
self.active_animations.remove(animation_id)
self.trigger_event(AnimationEvent.STOPPED, animation)
def on_event(self, event_type, handler):
"""Register an event handler"""
if event_type not in self.event_handlers:
self.event_handlers[event_type] = set()
self.event_handlers[event_type].add(handler)
def trigger_event(self, event_type, animation):
"""Trigger animation event handlers"""
if event_type in self.event_handlers:
for handler in self.event_handlers[event_type]:
handler(animation)
Animation Types
The Animation Manager supports various animation types:
- FadeAnimation: Gradual opacity changes
- MoveAnimation: Movement from one position to another
- SequenceAnimation: Series of animation frames
- ParallelAnimation: Multiple animations running simultaneously
- TypewriterAnimation: Character-by-character typing effect
- PunchCardAnimation: Specialized animation for punch card holes
Creating and Using Animations
To create and manage animations:
# Get the singleton instance
animation_manager = AnimationManager.instance()
# Create an animation
fade_anim = animation_manager.create_animation(
FadeAnimation,
target=self.message_label,
start_opacity=0.0,
end_opacity=1.0,
duration=500 # ms
)
# Create a sequence of animations
sequence = animation_manager.create_animation(
SequenceAnimation,
animations=[fade_anim, move_anim, type_anim],
loop=False
)
# Start the animation
animation_manager.start_animation(sequence.id)
# Handle animation events
animation_manager.on_event(AnimationEvent.COMPLETED, self.on_animation_complete)
Animation Synchronization
A key feature of the Animation Manager is synchronization between the GUI and hardware:
def create_synchronized_animation(self, gui_target, hardware_target):
"""Create animations that are synchronized between GUI and hardware"""
# Create GUI animation
gui_anim = self.create_animation(
FadeAnimation,
target=gui_target,
start_opacity=0.0,
end_opacity=1.0,
duration=500
)
# Create hardware animation
hw_anim = self.create_animation(
LEDAnimation,
target=hardware_target,
frames=self.generate_led_frames(),
duration=500
)
# Synchronize them with a parallel animation
sync_anim = self.create_animation(
ParallelAnimation,
animations=[gui_anim, hw_anim]
)
return sync_anim
Best Practices
When using the Animation Manager:
- Reuse Animations: Create animations once and reuse them
- Use Sequences: Combine animations into sequences for complex behaviors
- Keep Durations Reasonable: Very short animations may not render properly
- Clean Up: Make sure to stop animations when components are destroyed
- Handle Events: Always handle animation completion events
Performance Considerations
The Animation Manager has some performance implications:
- Memory Usage: Each animation object uses memory, so limit the number created
- CPU Usage: Complex animations may use significant CPU time
- Event Handling: Many event handlers can slow down the system
- Hardware Synchronization: Coordinating with hardware has overhead
Future Improvements
Planned enhancements to move the Animation Manager out of beta:
- Performance Optimization: Reduce CPU and memory usage
- More Animation Types: Additional animation options
- Better Interrupt Handling: Properly handle animation interruptions
- Timeline Support: More sophisticated animation sequencing
- Enhanced Hardware Sync: Better synchronization with physical hardware
Integration Examples
Splash Screen Animation
def create_splash_animation(self):
# Create fade-in animation for the logo
logo_fade = self.create_animation(
FadeAnimation,
target=self.logo_label,
start_opacity=0.0,
end_opacity=1.0,
duration=1000
)
# Create typing animation for the message
message_type = self.create_animation(
TypewriterAnimation,
target=self.message_label,
text="SYSTEM INITIALIZING...",
duration=2000
)
# Create sequence
splash_sequence = self.create_animation(
SequenceAnimation,
animations=[logo_fade, message_type]
)
return splash_sequence
Punch Card Animation
def create_punch_animation(self, message):
# Create animation for punching card holes
punch_anim = self.create_animation(
PunchCardAnimation,
target=self.punch_card,
message=message,
duration=len(message) * 200 # 200ms per character
)
# Create hardware LED animation
led_anim = self.create_animation(
LEDAnimation,
target=self.hardware_controller,
message=message,
duration=len(message) * 200
)
# Synchronize them
sync_anim = self.create_animation(
ParallelAnimation,
animations=[punch_anim, led_anim]
)
return sync_anim