Skip to content

Instantly share code, notes, and snippets.

@kdmukai
Created November 10, 2025 23:45
Show Gist options
  • Select an option

  • Save kdmukai/d28128218a2a750dda98b8aa7da289bb to your computer and use it in GitHub Desktop.

Select an option

Save kdmukai/d28128218a2a750dda98b8aa7da289bb to your computer and use it in GitHub Desktop.
Early draft of animated screensaver for Krux
def start(self):
"""Displays a screensaver until user presses a button or touch"""
anim_frame = 0
initial_offset = (TOTAL_LINES - len(SPLASH)) // 2
fg_color = theme.fg_color
bg_color = theme.bg_color
self.ctx.display.clear()
button_press = None
min_distance = 5 # fixed chars or rows
max_distance_x = int(self.ctx.display.usable_width()/FONT_WIDTH / 2)
max_distance_y = int(self.ctx.display.height()/FONT_HEIGHT / 2)
max_distance = max(max_distance_x, max_distance_y) # fixed chars or rows
max_anim_frame = max_distance
hold_at_completion = 1500 # millseconds
def initialize_deltas(deltas):
y_start = self.ctx.display.get_center_offset_y(len(SPLASH))
for row in SPLASH:
x_start = self.ctx.display.get_center_offset_x(row)
for i, char in enumerate(row):
if char == SPLASH_CHAR:
char_x = x_start + i*FONT_WIDTH
# Final target location is:
final_pt = (char_x, y_start)
# Randomized starting location:
offset_direction_x = -1 if randint(0, 1) == 1 else 1
offset_direction_y = -1 if randint(0, 1) == 1 else 1
offset_blocks_x = randint(min_distance, max_distance_x) * offset_direction_x
offset_blocks_y = randint(min_distance, max_distance_y) * offset_direction_y
start_pt = (
char_x + offset_blocks_x * FONT_WIDTH,
y_start + offset_blocks_y * FONT_HEIGHT
)
color = randint(0x0000, 0xFFFF)
deltas.append((start_pt, final_pt, offset_direction_x, offset_direction_y))
# Advance to the next line
y_start += FONT_HEIGHT
deltas = []
initialize_deltas(deltas)
erase_list = set()
while button_press is None:
# show animation on the screeen
# offset_y = anim_frame * FONT_HEIGHT
# self.ctx.display.fill_rectangle(
# 0,
# offset_y,
# self.ctx.display.width(),
# FONT_HEIGHT,
# bg_color,
# )
# if initial_offset <= anim_frame < len(SPLASH) + initial_offset:
# self.ctx.display.draw_hcentered_text(
# SPLASH[anim_frame - initial_offset], offset_y, fg_color, bg_color
# )
# anim_frame += 1
# if anim_frame > len(SPLASH) + 2 * initial_offset:
# anim_frame = 0
# bg_color, fg_color = fg_color, bg_color
if anim_frame > max_anim_frame:
# Reset to a new random sequence
anim_frame = 0
bg_color, fg_color = fg_color, bg_color
deltas = []
initialize_deltas(deltas)
button_press = self.ctx.input.wait_for_button(block=False, wait_duration=hold_at_completion)
self.ctx.display.fill_rectangle(0, 0, width=self.ctx.display.width(), height=self.ctx.display.height(), color=bg_color)
continue
render_list = set()
for i, (start_pt, final_pt, offset_direction_x, offset_direction_y) in enumerate(deltas):
cur_x = start_pt[0] - offset_direction_x * FONT_WIDTH * anim_frame
cur_y = start_pt[1] - offset_direction_y * FONT_HEIGHT * anim_frame
if offset_direction_x > 0:
cur_x = max(final_pt[0], cur_x)
else:
cur_x = min(final_pt[0], cur_x)
if offset_direction_y > 0:
cur_y = max(final_pt[1], cur_y)
else:
cur_y = min(final_pt[1], cur_y)
if min(cur_x, cur_y) < 0 or cur_x > self.ctx.display.usable_width() or cur_y > self.ctx.display.height():
continue
# if cur_x == final_pt[0] and cur_y == final_pt[1]:
# color = fg_color
render_list.add((cur_x, cur_y))
for x, y in render_list - (erase_list - render_list):
self.ctx.display.fill_rectangle(x=x, y=y, width=FONT_WIDTH, height=FONT_HEIGHT, color=fg_color)
for x, y in erase_list - render_list:
self.ctx.display.fill_rectangle(x=x, y=y, width=FONT_WIDTH, height=FONT_HEIGHT, color=bg_color)
anim_frame += 1
erase_list = render_list.copy()
# wait_duration(animation period) can be modified here
button_press = self.ctx.input.wait_for_button(block=False, wait_duration=SCREENSAVER_ANIMATION_WAIT)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment