# Standalone MicroPython Voice Animation: Breathing Idle # Exposes run(text="", frames=...) and runs automatically if executed directly. import time import math try: import board_config display = getattr(board_config, 'display_instance', None) except Exception: board_config = None display = None def draw_center_text(d, msg, y, w, scale=1, c=1): char_w = 8 * scale x = max(0, (w - len(msg) * char_w) // 2) if hasattr(d, 'text_large') and scale > 1: try: d.text_large(msg, x, y, scale, c) return except Exception: pass d.text(msg, x, y, c) def run(text="", frames=100): if not display: print("board_config.display_instance is not available. Skipping animation.") return width = getattr(display, 'width', 400) height = getattr(display, 'height', 300) cx, cy = width // 2, height // 2 label = text if text else "READY" frame = 0 try: while True: if frames is not None and frames > 0 and frame >= frames: break display.clear(0) # Cosine-based breathing curve: slow and smooth, scaling from 0 to 1 and back breath_scale = 0.5 + 0.5 * math.cos(frame * 0.07) # Draw three concentric breathing boxes # Base radii are scaled dynamically r1 = int(24 + 32 * breath_scale) r2 = int(14 + 18 * breath_scale) r3 = int(6 + 8 * breath_scale) # Outer box display.rect(cx - r1, cy - r1, r1 * 2, r1 * 2, 1) # Middle box display.rect(cx - r2, cy - r2, r2 * 2, r2 * 2, 1) # Inner solid core display.fill_rect(cx - r3, cy - r3, r3 * 2, r3 * 2, 1) # Draw small accent dots at the corners of the outer breathing box accent = r1 + 8 display.fill_rect(cx - accent - 2, cy - accent - 2, 4, 4, 1) display.fill_rect(cx + accent - 2, cy - accent - 2, 4, 4, 1) display.fill_rect(cx - accent - 2, cy + accent - 2, 4, 4, 1) display.fill_rect(cx + accent - 2, cy + accent - 2, 4, 4, 1) # Draw centered text label at the bottom draw_center_text(display, label, height - 30, width, scale=1, c=1) display.show() frame += 1 try: time.sleep_ms(65) except AttributeError: time.sleep(0.065) except KeyboardInterrupt: print("Animation interrupted by user.") if __name__ in ('__main__', '__name__'): run()