Here are two classic startup screens re-implemented in CircuitPython. To use them click the 'Download Project Bundle' button, then unzip the bundle and copy the code.py and libraries to your devices CIRCUITPY drive.
GameBoy
The GameBoy startup is simple but iconic. The Nintendo logo slides in from the top of the screen and when it reaches it stopping position a pleasant pling sound effect reminiscent of collection coins in Mario or other games. The CircuitPython version loads the logo Bitmap
with adafruit_imageload
and places it over the top of a background made from a solid color Bitmap
scaled to match the display size. The y position of the TileGrid
with the logo in it is updated at set intervals to slide down from the top of the display. Once it reaches the stopping position the pling sound wave file is played using the TLV320 DAC output.
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries # SPDX-License-Identifier: MIT import time from audiocore import WaveFile import audiobusio import board from displayio import Group, TileGrid, Bitmap, Palette import supervisor import adafruit_imageload import adafruit_tlv320 from adafruit_fruitjam.peripherals import request_display_config # how long between animation frames ANIMATE_INTERVAL = 1 / 45 background_color = 0xE1F7CE i2c = board.I2C() dac = adafruit_tlv320.TLV320DAC3100(i2c) dac.configure_clocks(sample_rate=44100, bit_depth=16) # for headphone jack ouput dac.headphone_output = True dac.headphone_volume = -15 # dB # for speaker JST output # dac.speaker_output = True # dac.speaker_volume = -15 # dB wave_file = open("gameboy_startup/gameboy_pling.wav", "rb") wave = WaveFile(wave_file) audio = audiobusio.I2SOut(board.I2S_BCLK, board.I2S_WS, board.I2S_DIN) # display setup request_display_config(320, 240) display = supervisor.runtime.display # group to hold all visual elements main_group = Group() # Bitmap for background color bg_bmp = Bitmap(display.width // 20, display.height // 20, 1) bg_palette = Palette(1) bg_palette[0] = background_color bg_tg = TileGrid(bg_bmp, pixel_shader=bg_palette) # group to scale the background bitmap up to display size bg_group = Group(scale=20) bg_group.append(bg_tg) main_group.append(bg_group) # Bitmap for logo logo, palette = adafruit_imageload.load("gameboy_startup/gameboy_logo.bmp") logo_tg = TileGrid(logo, pixel_shader=palette) main_group.append(logo_tg) # place it in the center horizontally and above the top of the display logo_tg.x = display.width // 2 - logo_tg.tile_width // 2 logo_tg.y = -logo_tg.tile_height # y pixel location to stop logo at STOP_Y = display.height * 0.4 - logo_tg.tile_height // 2 display.root_group = main_group time.sleep(1.5) last_animate_time = time.monotonic() played_audio = False display.auto_refresh = False while True: now = time.monotonic() # if it's time to animate and the logo isn't to the # stopping position yet if last_animate_time + ANIMATE_INTERVAL <= now and logo_tg.y < STOP_Y: # update the timestamp last_animate_time = now # move the logo down by a pixel logo_tg.y += 1 display.refresh() # if the logo has reached the stop position if logo_tg.y >= STOP_Y and not played_audio: played_audio = True # play the audio pling audio.play(wave) while audio.playing: pass
Mac System 7.5
With the release of System 7.5, Apple added a progress bar to the startup screen, as well as some icons along the bottom stylized like jigsaw puzzle pieces. The CircuitPython implementation uses an OnDiskBitmap
showing an image that contains the background and welcome message box. A progress bar and series of TileGrids
containing icons are layered on top of the background. The progress bar is updated over time, and at specified intervals a new icon gets revealed by settings its hidden
property to False
.
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries # SPDX-License-Identifier: MIT import time from audiocore import WaveFile import audiobusio import board import supervisor from displayio import Group, TileGrid, OnDiskBitmap import adafruit_tlv320 from adafruit_fruitjam.peripherals import request_display_config from adafruit_progressbar.horizontalprogressbar import ( HorizontalFillDirection, HorizontalProgressBar, ) # DAC setup i2c = board.I2C() dac = adafruit_tlv320.TLV320DAC3100(i2c) dac.configure_clocks(sample_rate=44100, bit_depth=16) # for headphone jack ouput dac.headphone_output = True dac.headphone_volume = -15 # dB # for speaker JST output # dac.speaker_output = True # dac.speaker_volume = -15 # dB # Chime audio setup wave_file = open("mac_startup/mac_chime.wav", "rb") wave = WaveFile(wave_file) audio = audiobusio.I2SOut(board.I2S_BCLK, board.I2S_WS, board.I2S_DIN) # Display setup request_display_config(640, 480) display = supervisor.runtime.display display.auto_refresh = False # group to hold visual all elements main_group = Group() display.root_group = main_group display.refresh() # background image bg_bmp = OnDiskBitmap("mac_startup/mac_startup_bg.bmp") bg_tg = TileGrid(bg_bmp, pixel_shader=bg_bmp.pixel_shader) main_group.append(bg_tg) # Icons for bottom left icons = [] for i in range(6): odb = OnDiskBitmap("mac_startup/mac_startup_icon{0}.bmp".format(i)) tg = TileGrid(odb, pixel_shader=odb.pixel_shader) icons.append( { "bmp": odb, "tg": tg, } ) tg.x = 10 + ((33 + 8) * i) tg.y = display.height - tg.tile_height - 10 tg.hidden = True if i < 5: odb.pixel_shader.make_transparent(0) main_group.append(tg) # progress bar in the welcome box progress_bar = HorizontalProgressBar( (147, 138), (346, 7), direction=HorizontalFillDirection.LEFT_TO_RIGHT, min_value=0, max_value=800, fill_color=0xC7BEFD, outline_color=0x000000, bar_color=0x3F3F3F, margin_size=0, ) main_group.append(progress_bar) # play the chime sound audio.play(wave) while audio.playing: pass # start drawing the visual elements display.auto_refresh = True time.sleep(1) start_time = time.monotonic() while True: elapsed = time.monotonic() - start_time # if we haven't reached the end yet if elapsed * 100 <= 800: # update the progress bar progress_bar.value = elapsed * 100 else: # reached the end animation # set progress bar to max value progress_bar.value = 800 # loop over all icons for index, icon in enumerate(icons): # if it's time for the current icon to show, and it's still hidden if (elapsed - 1) > index and icon["tg"].hidden: # make the current icon visible icon["tg"].hidden = False
Page last edited June 13, 2025
Text editor powered by tinymce.