Created
November 10, 2025 23:45
-
-
Save kdmukai/d28128218a2a750dda98b8aa7da289bb to your computer and use it in GitHub Desktop.
Early draft of animated screensaver for Krux
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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