# Standalone MicroPython Voice Animation: Wake Attention # 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 "HI, I'M LISTENING" frame = 0 try: while True: if frames is not None and frames > 0 and frame >= frames: break display.clear(0) # Left and Right eye center X coordinates left_cx = cx - 55 right_cx = cx + 55 eye_y = cy - 10 # State cycle to control pupil gaze offset (look center, look left, look right) gaze_state = (frame // 16) % 4 gaze_offset = 0 if gaze_state == 1: gaze_offset = -12 # Look left elif gaze_state == 3: gaze_offset = 12 # Look right # Blink cycle: close eyes for a few frames periodically is_blinking = (frame % 22) in (0, 1, 2) if is_blinking: # Closed eyes: draw simple horizontal lines across the eye spaces display.line(left_cx - 28, eye_y, left_cx + 28, eye_y, 1) display.line(left_cx - 28, eye_y + 1, left_cx + 28, eye_y + 1, 1) # thicker display.line(right_cx - 28, eye_y, right_cx + 28, eye_y, 1) display.line(right_cx - 28, eye_y + 1, right_cx + 28, eye_y + 1, 1) # thicker else: # Open eyes: draw outer rounded rectangular bounding frames # Left eye border display.rect(left_cx - 32, eye_y - 22, 64, 44, 1) display.rect(left_cx - 31, eye_y - 21, 62, 42, 1) # Right eye border display.rect(right_cx - 32, eye_y - 22, 64, 44, 1) display.rect(right_cx - 31, eye_y - 21, 62, 42, 1) # Draw pupils inside, shifted by the gaze offset display.fill_rect(left_cx - 10 + gaze_offset, eye_y - 10, 20, 20, 1) display.fill_rect(right_cx - 10 + gaze_offset, eye_y - 10, 20, 20, 1) # Draw small cute highlights inside pupils display.fill_rect(left_cx - 6 + gaze_offset, eye_y - 6, 6, 6, 0) display.fill_rect(right_cx - 6 + gaze_offset, eye_y - 6, 6, 6, 0) # 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(60) except AttributeError: time.sleep(0.06) except KeyboardInterrupt: print("Animation interrupted by user.") if __name__ in ('__main__', '__name__'): run()