Add RLCD animations and screensavers
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
# 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()
|
||||
Reference in New Issue
Block a user