The Fruit Jam OS Launcher supports showing a screensaver after a specified period of inactivity. By default there is no screensaver set, you can enable it by adding the configuration to launcher.conf.json or by using the built-in ScreenSave preview and selector app.
ScreenSave Preview & Selector App
As of January 2026, the ScreenSave app has been updated to support previewing all screensavers loaded on the Fruit Jam and to allow saving a selection for the one to use by the Fruit Jam OS Launcher.
As of January 2026, the ScreenSave app has been updated to support previewing all screensavers loaded on the Fruit Jam and to allow saving a selection for the one to use by the Fruit Jam OS Launcher.
Launch the ScreenSave app, then use the right and left arrow keys on the keyboard, or click the arrow buttons on the screen to see previews of all of the screensavers currently loaded on the device. Once you've found the one that you like press enter, or click the save icon to set it as the screensaver to use. Once your finished press the Escape key to exit.
Launcher Config File
Add a "screensaver" key to the JSON config file with an object as the value. Inside of the object specify a "module" and optionally a "class". The "module" value needs to be a path to a Python code file that contains a valid ScreenSaver class in it, but without the .py file extension. The "class" value is a string with the name of a specific class inside the Python file to use as the screensaver. If omitted the launcher will automatically try to find a class that has ScreenSaver at the end of its name to use. If there are more than one ScreenSaver class in the file, or if the class doesn't use the same naming convention, then "class" must be specified in launcher.conf.json.
{
"screensaver": {
"module": "/apps/Screensavers/flying_toasters_screensaver",
"class": "FlyingToasterScreenSaver"
}
}
Included Screensavers
There are a few screensavers included with Fruit Jam OS. These can be configured 'out of the box' with no additional download or installation needed. Simply add the module name inside of launcher.conf.json and reload the launcher for them to take effect.
This is one of the classic screensavers from After Dark. Winged toasters and pieces of toast fly across the screen in a dark void. This screensaver supports the use of "screensaver.background_color" key in launcher.conf.json to set the desired background color. Valid values are strings containing a hex colors like "0x220022" or the word "transparent".
To use the Flying Toaster screensaver, set its module in the launcher.conf.json file.
"screensaver": {
"module": "/apps/Screensavers/flying_toasters_screensaver"
},
"screensaver.background_color": "transparent"
This is another favorite from After Dark. It depicts an aquarium with a gravel floor, plant, occasional bubbles, and of course loads of exotic fish swimming about. This screensaver supports the use of "screensaver.background_color" key in launcher.conf.json to set the desired background color. Valid values are strings containing a hex colors like "0x220022" or the word "transparent".
To use the Fish Tank screensaver, set its module in the launcher.conf.json file.
"screensaver": {
"module": "/apps/Screensavers/fish_screensaver"
},
"screensaver.background_color": "0x001122"
In this screensaver the Fruit Jam logo bounces around the screen diagonally changing colors each time it hits a wall. Keep watching and maybe you'll be lucky enough to catch it bounce perfectly out of a corner.
To use the Bouncing Logo screensaver, set its module in the launcher.conf.json file.
"screensaver": {
"module": "/apps/Screensavers/bouncing_logo_screensaver"
},
Picture Frame
This is a simple slideshow style photo screensaver. It will cycle through photos contained in a specified folder showing each on the display for a configurable duration before advancing to the next.
To use the Pixel Frame screensaver set its module in the launcher.conf.json file.
The time to show each image, which folder to load images from, and whether to shuffle images can be set with "DisplaySeconds", "Shuffle", and "PictureDirectory" values inside of a "PictFrame"object in the launcher.conf.json file.
"screensaver": {
"module": "/apps/Screensavers/picture_frame_screensaver"
},
"PictFrame": {
"DisplaySeconds": 25,
"Shuffle": true,
"PictureDirectory": "/sd/PictFrame",
}
Random
This will choose a random screensaver from all of the ones found inside of /apps/Screensavers/. Each time the launcher is loaded it will select another screensaver at random. As you move between apps it will choose different screensavers to use when idle.
To use the Random screensaver, set its module in the launcher.conf.json file.
"screensaver": {
"module": "/apps/Screensavers/random_screensaver"
},
Custom Screensavers
It's also possible to implement your own custom screen savers. To create one, define a Python class that extends displayio.Group, provides a display_size attribute, and implements a tick() function.
All visual elements of the screensaver should get added to the self Group instance. The tick() function should do any animation or other visual updates to the displayed elements and return True if the display needs to refresh or False if not. The display_size attribute gets set to a tuple containing the desired screen resolution to render the screensaver.
Once you've created the Python file containing your screensaver class, set the appropriate path to the module in the launcher.conf.json file.
"screensaver": {
"module": "/apps/my_custom_screensaver/awesome_screensaver"
},
A copy of the bouncing logo screensaver is embedded below which illustrates a basic screensaver implementation. Reference it and the code for the other built-in screensavers as needed while creating your own.
import os
import random
import time
from displayio import Group, OnDiskBitmap, TileGrid, Bitmap, Palette
import adafruit_imageload
class BouncingLogoScreenSaver(Group):
display_size = (640, 480)
direction: list = [3, 3]
logo_tg: TileGrid = None
last_move_time = 0
move_cooldown = 0.05 # seconds
colors = [0xffffff, 0xff0000, 0xffff00, 0x00ffff, 0xff00ff, 0x0000ff, 0x00ff00]
color_index = 0
def __init__(self):
super().__init__()
self.init_graphics()
def init_graphics(self):
bg_bmp = Bitmap(self.display_size[0] // 20, self.display_size[1] // 20, 1)
bg_palette = Palette(1)
bg_palette[0] = 0x000000
bg_tg = TileGrid(bitmap=bg_bmp, pixel_shader=bg_palette)
bg_group = Group(scale=20)
bg_group.append(bg_tg)
self.append(bg_group)
os.chdir("/".join(__file__.split("/")[:-1]))
logo_bmp, logo_bmp_pixelshader = adafruit_imageload.load("fruit_jam_logo.bmp")
self.logo_tg = TileGrid(bitmap=logo_bmp, pixel_shader=logo_bmp_pixelshader)
self.logo_tg.x = random.randint(20, self.display_size[0] - self.logo_tg.tile_width - 20)
self.append(self.logo_tg)
def change_color(self):
self.color_index += 1
if self.color_index >= len(self.colors):
self.color_index = 0
self.logo_tg.pixel_shader[1] = self.colors[self.color_index]
def tick(self):
now = time.monotonic()
if now - self.last_move_time > self.move_cooldown:
self.last_move_time = now
# move one step in direction
self.logo_tg.x += self.direction[0]
self.logo_tg.y += self.direction[1]
# bounce left wall
if self.logo_tg.x <= 0:
self.direction[0] = 3
self.change_color()
# bounce right wall
if self.logo_tg.x + self.logo_tg.tile_width >= self.display_size[0]:
self.direction[0] = -3
self.change_color()
# bounce top wall
if self.logo_tg.y <= 0:
self.direction[1] = 3
self.change_color()
# bounce bottom wall
if self.logo_tg.y + self.logo_tg.tile_height >= self.display_size[1]:
self.direction[1] = -3
self.change_color()
return True
return False
Page last edited January 13, 2026
Text editor powered by tinymce.