# Standalone MicroPython Voice Animation: Caption Scan # Exposes run(text="", frames=...) and runs automatically if executed directly. import time try: import board_config display = getattr(board_config, 'display_instance', None) except Exception: board_config = None display = None def wrap_text(msg, max_chars=36): words = msg.split() lines = [] curr = "" for w in words: if len(curr) + len(w) + 1 > max_chars: lines.append(curr) curr = w else: curr = (curr + " " + w).strip() if curr: lines.append(curr) return lines 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 # Simulated text sequence if no real-time caption text is supplied default_script = [ "RECEIVING VOICE PACKETS...", "DECODING AUDIO STREAM...", "MATCHING PHONEME VECTORS...", "EXTRACTING INTENT AND CONTEXT...", "STT METRICS: LATENCY 42MS", "TRANSCRIPTION STABILIZED.", "AWAITING PIPELINE RESPONSE..." ] frame = 0 try: while True: if frames is not None and frames > 0 and frame >= frames: break display.clear(0) # Draw outer scan framing display.rect(15, 15, width - 30, height - 50, 1) # Draw moving scanner bar line scan_y = 20 + ((frame * 6) % (height - 60)) display.line(20, scan_y, width - 20, scan_y, 1) # Draw static top status line display.text("SPEECH-TO-TEXT DECODER", 25, 25, 1) display.line(25, 37, width - 25, 37, 1) # Determine what text to write based on typewriter frame counter if text: lines = wrap_text(text, max_chars=(width - 50) // 8) char_limit = int(frame * 2.5) chars_drawn = 0 for idx, line in enumerate(lines): if chars_drawn >= char_limit: break line_to_draw = line[:char_limit - chars_drawn] display.text(line_to_draw, 25, 55 + idx * 18, 1) chars_drawn += len(line) else: # Typewriter animation of simulated lines active_line_idx = (frame // 15) % len(default_script) char_limit = int((frame % 15) * 3) # Show previously printed lines in full start_line = max(0, active_line_idx - 5) for idx in range(start_line, active_line_idx): display.text(default_script[idx], 25, 55 + (idx - start_line) * 18, 1) # Typewriter effect on the current line curr_line_text = default_script[active_line_idx][:char_limit] display.text(curr_line_text, 25, 55 + (active_line_idx - start_line) * 18, 1) # Flash a cursor at the end of the typing line if (frame // 3) % 2 == 0: cursor_x = 25 + len(curr_line_text) * 8 cursor_y = 55 + (active_line_idx - start_line) * 18 display.fill_rect(cursor_x, cursor_y, 8, 8, 1) # Draw bottom transcription indicator display.text("TRANSCRIBING...", 25, height - 25, 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()