# Fruit Jam OS

## Overview

![Fruit Jam OS launcher showing app icons for the 1st page of apps running on a Fruit Jam device with a USB keyboard plugged in and displayed on a mini DVI compatible display.](https://cdn-learn.adafruit.com/assets/assets/000/139/114/medium800/circuitpython_fruit_jam_os_overview_hero.png?1755814294 )

Fruit Jam OS is a self contained basic operating system, written in CircuitPython, that runs on the Fruit Jam device. Along with the&nbsp;[Fruit Jam Boot Animation](https://learn.adafruit.com/startup-screens/fruit-jam-os), it includes a launcher that you can navigate with USB keyboard or mouse, an editor for viewing and modifying code files, and several built-in apps and games from other Adafruit Learn Guide projects.

It's meant to be a somewhat updated take on the experience provided by the Commodore 64 and other early computer hardware fused with a DIY game console.

## Parts
### Adafruit Fruit Jam - Mini RP2350 Computer

[Adafruit Fruit Jam - Mini RP2350 Computer](https://www.adafruit.com/product/6200)
We were catching up on a recent [hackaday hackchat with eben upton](https://hackaday.io/event/202122-raspberry-pi-hack-chat-with-eben-upton)&nbsp;and learned some fun facts: such as the DVI hack for the RP2040 was inspired by <a...></a...>

Out of Stock
[Buy Now](https://www.adafruit.com/product/6200)
[Related Guides to the Product](https://learn.adafruit.com/products/6200/guides)
![Angled shot of assembled mini computer PCB with plate.](https://cdn-shop.adafruit.com/640x480/6200-10.jpg)

### Mini Chiclet Keyboard - USB Wired - Black

[Mini Chiclet Keyboard - USB Wired - Black](https://www.adafruit.com/product/1736)
Add a good quality, slim keyboard to your&nbsp;Raspberry Pi, Beagle Bone Black, or other single-board-computer with this sleek black chiclet keyboard. It's a full QWERTY keyboard with a USB cable and is compatible with all operating systems. We tried many keyboards to find one that felt...

In Stock
[Buy Now](https://www.adafruit.com/product/1736)
[Related Guides to the Product](https://learn.adafruit.com/products/1736/guides)
![Angled shot of a Black woman's silver-blue manicured hands on a slim, black keyboard.](https://cdn-shop.adafruit.com/640x480/1736-04.jpg)

### USB Wired Mouse - Two Buttons plus Wheel

[USB Wired Mouse - Two Buttons plus Wheel](https://www.adafruit.com/product/2025)
This is a mouse. &nbsp;A nice, simple mouse. &nbsp;No bells or whistles. &nbsp;Just a mouse.  
  
But that doesn't mean it's not the best simple mouse!&nbsp; We compared a few and liked this one quite a bit. &nbsp;It's optical for good resolution and precision, has two...

In Stock
[Buy Now](https://www.adafruit.com/product/2025)
[Related Guides to the Product](https://learn.adafruit.com/products/2025/guides)
![Angled Shot of the USB Wired Mouse - Two Buttons plus Wheel](https://cdn-shop.adafruit.com/640x480/2025-05.jpg)

### HDMI Cable - 1 meter

[HDMI Cable - 1 meter](https://www.adafruit.com/product/608)
Connect two HDMI devices together with this basic HDMI cable. It has nice molded grips for easy installation, and is 1 meter long (about 3 feet). This is a HDMI 1.3 cable.

We're now stocking a very fancy Official Raspberry Pi cable with overmolding and a Pi logo. Please note...

In Stock
[Buy Now](https://www.adafruit.com/product/608)
[Related Guides to the Product](https://learn.adafruit.com/products/608/guides)
![Official Raspberry Pi HDMI Cable - 1 meter](https://cdn-shop.adafruit.com/640x480/608-03.jpg)

### USB Type A to Type C Cable - approx 1 meter / 3 ft long

[USB Type A to Type C Cable - approx 1 meter / 3 ft long](https://www.adafruit.com/product/4474)
As technology changes and adapts, so does Adafruit. This&nbsp;&nbsp; **USB Type A to Type C** cable will help you with the transition to USB C, even if you're still totin' around a USB Type A hub, computer or laptop.

USB C is the latest industry-standard connector for...

In Stock
[Buy Now](https://www.adafruit.com/product/4474)
[Related Guides to the Product](https://learn.adafruit.com/products/4474/guides)
![Angled shot of a coiled black, USB-C to USB-A cable.](https://cdn-shop.adafruit.com/640x480/4474-02.jpg)

### 7" Display 1280x800 (720p) IPS + Speakers - HDMI/VGA/NTSC/PAL

[7" Display 1280x800 (720p) IPS + Speakers - HDMI/VGA/NTSC/PAL](https://www.adafruit.com/product/1667)
Yes, this is an adorable small HDMI television with incredibly high resolution **and built in 3W stereo speakers**! We tried to get the smallest possible HDMI/VGA display with high-res, high-contrast visibility. The visible display measures only 7" (17.8cm) diagonal, and the TFT comes...

In Stock
[Buy Now](https://www.adafruit.com/product/1667)
[Related Guides to the Product](https://learn.adafruit.com/products/1667/guides)
![Front view of assembled and powered on HDMI 4 Pi - 7" Display. The monitor displays a desktop background with a raspberry logo.](https://cdn-shop.adafruit.com/640x480/1667-00.jpg)

# Fruit Jam OS

## Install CircuitPython

[CircuitPython](https://github.com/adafruit/circuitpython) is a derivative of [MicroPython](https://micropython.org) designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the **CIRCUITPY** drive to iterate.

## CircuitPython Quickstart

Follow this step-by-step to quickly get CircuitPython running on your board.

Warning: Please use the latest release of 10.x or higher for the Fruit Jam. Also use the latest libraries for the best functionality.

[Download the latest version of CircuitPython for this board via circuitpython.org](https://circuitpython.org/board/adafruit_fruit_jam/)
 **Click the link above to download the latest CircuitPython UF2 file.**

Save it wherever is convenient for you.

![install_circuitpython_on_rp2040_RP2040_UF2_downloaded.jpg](https://cdn-learn.adafruit.com/assets/assets/000/101/655/medium640/install_circuitpython_on_rp2040_RP2040_UF2_downloaded.jpg?1618943202)

![reset and boot highlighted](https://cdn-learn.adafruit.com/assets/assets/000/138/708/medium800/adafruit_products_Resetboot.jpg?1754331128 )

To enter the bootloader, hold down the **BOOT/**** BOOTSEL button**(highlighted in red above), and while continuing to hold it (don't let go!), press and release the**reset button**(highlighted in red or blue above).&nbsp;**Continue to hold the BOOT/BOOTSEL button until the RP2350 drive appears!**

If the drive does not appear, release all the buttons, and then repeat the process above.

You can also start with your board unplugged from USB, press and hold the BOOTSEL button (highlighted in red above), continue to hold it while plugging it into USB, and wait for the drive to appear before releasing the button.

A lot of people end up using charge-only USB cables and it is very frustrating! **Make sure you have a USB cable you know is good for data sync.**

You will see a new disk drive appear called **RP2350**.

&nbsp;

Drag the **adafruit-circuitpython-_boardname_-_language_-_version_.uf2** file to **RP2350.**

![install_circuitpython_on_rp2350_Screenshot_2024-09-11_111518.png](https://cdn-learn.adafruit.com/assets/assets/000/132/253/medium640/install_circuitpython_on_rp2350_Screenshot_2024-09-11_111518.png?1726067809)

![install_circuitpython_on_rp2350_Screenshot_2024-09-11_111742.png](https://cdn-learn.adafruit.com/assets/assets/000/132/254/medium640/install_circuitpython_on_rp2350_Screenshot_2024-09-11_111742.png?1726067866)

The **RP2350** drive will disappear and a new disk drive called **CIRCUITPY** will appear.

That's it, you're done! :)

![install_circuitpython_on_rp2350_Screenshot_2024-09-11_111843.png](https://cdn-learn.adafruit.com/assets/assets/000/132/255/medium640/install_circuitpython_on_rp2350_Screenshot_2024-09-11_111843.png?1726067932)

## Safe Mode

You want to edit your **code.py** or modify the files on your **CIRCUITPY** drive, but find that you can't. Perhaps your board has gotten into a state where **CIRCUITPY** is read-only. You may have turned off the **CIRCUITPY** drive altogether. Whatever the reason, safe mode can help.

Safe mode in CircuitPython does not run any user code on startup, and disables auto-reload. This means a few things. First, safe mode _bypasses any code in_ **boot.py** (where you can set **CIRCUITPY** read-only or turn it off completely). Second, _it does not run the code in_ **code.py**. And finally, _it does not automatically soft-reload when data is written to the_ **CIRCUITPY** _drive_.

Therefore, whatever you may have done to put your board in a non-interactive state, safe mode gives you the opportunity to correct it without losing all of the data on the **CIRCUITPY** drive.

### Entering Safe Mode
To enter safe mode when using CircuitPython, plug in your board or hit reset (highlighted in red above). Immediately after the board starts up or resets, it waits 1000ms. On some boards, the onboard status LED (highlighted in green above) will blink yellow during that time. If you press reset during that 1000ms, the board will start up in safe mode. It can be difficult to react to the yellow LED, so you may want to think of it simply as a slow double click of the reset button. (Remember, a fast double click of reset enters the bootloader.)

### In Safe Mode

If you successfully enter safe mode on CircuitPython, the LED will intermittently blink yellow three times.

If you connect to the serial console, you'll find the following message.

```terminal
Auto-reload is off.
Running in safe mode! Not running saved code.

CircuitPython is in safe mode because you pressed the reset button during boot. Press again to exit safe mode.

Press any key to enter the REPL. Use CTRL-D to reload.
```

You can now edit the contents of the **CIRCUITPY** drive. Remember, _your code will not run until you press the reset button, or unplug and plug in your board, to get out of safe mode._

## Flash Resetting UF2

If your board ever gets into a really _weird_ state and CIRCUITPY doesn't show up as a disk drive after installing CircuitPython, try loading this 'nuke' UF2 to RP2350. which will do a 'deep clean' on your Flash Memory. **You will lose all the files on the board** , but at least you'll be able to revive it! After loading this UF2, follow the steps above to re-install CircuitPython.

[Download flash erasing "nuke" UF2 for RP2350](https://cdn-learn.adafruit.com/assets/assets/000/132/526/original/rp2350_flash_nuke.uf2)
# Fruit Jam OS

## Get Fruit Jam OS

Fruit Jam OS is available in multiple languages: you download the zip file for the language of your choice. Each different language .zip contains a [lvfontio](https://docs.circuitpython.org/en/latest/shared-bindings/lvfontio/index.html) compatible file that is capable of displaying the characters for that language. To install Fruit Jam OS, you need to first [install CircuitPython on your Fruit Jam](https://learn.adafruit.com/adafruit-fruit-jam/install-circuitpython) (described on the previous page). Once you have CircuitPython loaded on your Fruit Jam, the installation of Fruit Jam OS can begin.

## Download

Click the button below to download the latest release of Fruit Jam OS for the US English language. For other languages go to the [Fruit Jam OS release page](https://github.com/adafruit/Fruit-Jam-OS/releases/latest/) and look for your desired language file under **Assets**.

[en_US Fruit Jam OS Download](https://github.com/adafruit/Fruit-Jam-OS/releases/latest/download/fruit_jam_en_US.zip)
Next unzip the downloaded file. Make a backup of your existing **code.py** under a different name on the&nbsp; **CIRCUITPY** drive (if you have an old program you want to keep). Then copy all of the follow files and folders from the unzipped file to the **CIRCUITPY** drive:

- **apps/**
- **boot\_animation/**
- **fonts/**
- **launcher\_assets/**
- **lib/**
- **boot.py**
- **boot\_animation.py**
- **code.py**
- **settings.toml**

![Files contained within Fruit Jam release downloaded zip](https://cdn-learn.adafruit.com/assets/assets/000/139/101/medium640/circuitpython_fruit_jam_os_release_files.png?1755632112)

If you already have a **settings.toml** file with settings you want to keep, then merge the contents together using a text editor.

The copying process can take a few minutes, be patient.

Once it's complete, you're done! Make sure the Fruit Jam is plugged in to a compatible display.

Primary: You need to plug a USB keyboard and/or USB mouse into the Fruit Jam, before power up, to use the Fruit Jam OS user interface.

Press the reset button on the device. It will reboot, play the boot animation, and then go into the launcher.

# Fruit Jam OS

## Boot Sequence

The standard [CircuitPython boot sequence and logic](https://learn.adafruit.com/welcome-to-circuitpython/troubleshooting#circuitpython-7-dot-0-0-and-later-2978455) applies when you are running Fruit Jam OS. This dictates what CircuitPython will do when it first boots up. By default with a standard single reset or normal boot up, CircuitPython will first run the **boot.py** file, if it exists, and following that run the **code.py** file that we are familiar with.

Fruit Jam OS changes the default flow a little bit by inserting **boot\_animation.py** between **boot.py** and **code.py** , as well as offering a mechanism to skip the boot animation and launcher. The diagram below outlines the startup behavior of Fruit Jam OS.

![Flow chart showing boot.py determining whether a next_code_file argument is set, if so, the specific file is launched. If not then boot_animation.py followed by code.py are launched.](https://cdn-learn.adafruit.com/assets/assets/000/138/588/medium800/circuitpython_boot_sequence.png?1753894544 )

## Launching Other Python Files

A technique that foundational to how Fruit Jam OS works is launching different CircuitPython code files on a reload. The boot animation, launcher, and editor all make use of this technique. The way this works in CircuitPython is by using&nbsp;[`supervisor.set_next_code_file()`](https://docs.circuitpython.org/en/latest/shared-bindings/supervisor/index.html#supervisor.set_next_code_file). This function accepts a string with a filename of a CircuitPython code file to launch and a handful of optional arguments to vary its behavior. See the documentation for full details.&nbsp;

After you call `supervisor.set_next_code_file()`, the next time CircuitPython starts up, it will run the specified file instead of&nbsp; **code.py.** Fruit Jam OS calls this function and then calls `supervisor.reload()` immediately afterward to force CircuitPython to reload and run the file specified before. Here is an example of a typical usage from the end of the boot animation:

```auto
supervisor.set_next_code_file("code.py")
supervisor.reload()
```

As noted, Fruit Jam OS adds a bit of extra logic on top of the standard boot sequence. During a standard boot into Fruit Jam OS there are 3 stages within the boot process:

- **boot.py** - The **boot.py** file included with Fruit Jam OS first checks for arguments passed to it using the [adafruit\_argv\_file](https://github.com/adafruit/Adafruit_CircuitPython_Argv_File) module. There are a few possible arguments that will affect how it behaves and what happens next. They're detailed below in the _boot arguments_ section. During a standard boot up, there will be no arguments and the boot sequence will move on to the next stage, launching **boot\_animation.py**.
- **boot\_animation.py** - This file displays the cheerful and iconic Fruit Jam boot animation on the screen, and plays the lovely jingle over the connected speakers or headphones. See the [Startup Screens](https://learn.adafruit.com/startup-screens/overview) guide for more details about the boot animation and a deeper dive into the code. Once the animation is complete, **code.py** will be launched.
- **code.py** - In Fruit Jam OS, **code.py** contains the launcher program. It shows the apps that are loaded on your device split into pages of 6 at a time. You can navigate them with either USB keyboard or mouse and select an app in order to launch it.

## **boot.py** Arguments

The Fruit Jam OS **boot.py** script checks for arguments that were passed to it via the [adafruit\_argv\_file](https://github.com/adafruit/Adafruit_CircuitPython_Argv_File) module. The `adafruit_argv_file` API is similar to `sys.argv` in CPython. Arguments are accessed as a `list` containing 0 or more values. Since it's a list, arguments are indexed starting at `0`. The possible arguments that the Fruit Jam OS **boot.py** file will look for and use are:

- `0`: storage `readonly` boolean flag. Setting to `False` means mount to mount the flash filesystems as writable to CircuitPython. `True` means mount read-only to CircuitPython. The built-in Editor app uses this argument when the user requests that the drive be mounted as writable.
- `1`: `next_code_file` A string containing the name of a CircuitPython code file to launch instead of the default **boot\_animation.py**. This can be used to skip the boot animation and launch directly into a different app. The built-in Editor app uses it to launch directly back to itself after rebooting to have the flash mounted as writable.
- `2-N`: All remaining arguments will get passed to the next code file that is launched. This is also used by the Editor in order to specify which file it should open up after having the storage remounted.&nbsp;

# Fruit Jam OS

## Launcher

![Fruit Jam OS Launcher showing a 2x3 grid of app icons](https://cdn-learn.adafruit.com/assets/assets/000/139/102/medium800/circuitpython_fruit_jam_os_launcher.png?1755794372 )

The Fruit Jam OS Launcher shows all of the apps currently loaded onto the device in pages of 2x3 grids of icons.

The launcher will automatically adapt to the display resolution that is set in the **settings.toml** file. If no display settings are found in&nbsp; **settings.toml** it will use whatever resolution the CircuitPython core started with.&nbsp;For details on configuring display size and other parameters using **settings.toml** see: [Setting Monitor Values via Environment Variables](https://learn.adafruit.com/using-dvi-video-in-circuitpython/setting-monitor-values-via-environment-variables).

## Navigation

You can navigate the launcher menu with a USB keyboard and/or USB mouse plugged into one of the Fruit Jam USB Host ports.&nbsp;

### Keyboard

You can navigate the menu with a keyboard by using the arrow keys to move the focus indicator around to the choose different icons or the arrow buttons. In addition, you can use the following hotkeys:

- Press **E** to launch the editor app and open it the code file for the currently chosen app icon. For example, in the image above the Breakout app is chosen. If you press the E key the editor would open with the Breakout game's **code.py** file for viewing/editing.
- Press **Enter** to launch the currently chosen app, or change pages if an arrow is chosen.
- Pressing any number **1-9** will go directly to the menu page for that number, if it exists.

### Mouse

With a mouse simply click on an icon to launch that app, or click on an arrow to change pages.

## Customize Launcher Colors

The Fruit Jam OS launcher colors are customizable by using a **launcher.conf.json** file. Create this file in the top level of the **CIRCUITPY** drive and then set up to four custom color values inside of a `"palette"` key in a JSON dictionary. Here is a sample launcher config with a few extra color palettes defined for easily swapping between them.

```auto
{
  "palette": {
    "bg": "0x000000",
    "fg": "0x00ff00",
    "arrow": "0x004400",
    "accent": "0x008800"
  },
  "matrixpalette": {
    "bg": "0x000000",
    "fg": "0x00ff00",
    "arrow": "0x004400",
    "accent": "0x008800"
  },
  "c64palette": {
    "bg": "0x0000FF",
    "fg": "0xFF0000",
    "arrow": "0x00FF00",
    "accent": "0xFFFF00"
  }
}
```

Inside of the `"palette"` dictionary, you can change the following colors:

- `bg` - Background color of the launcher
- `fg` - Foreground color, which is used for the text
- `arrow` - Color of the arrow buttons on the left and right sides
- `accent` - Color of the focus indicator that is shown on app titles and the arrow buttons.

The values for these settings should be strings containing a valid 6 digit hex color value i.e. `"0x00ff00"`.&nbsp;

Whichever colors are in the&nbsp;`"palette"` key will take effect; any other alternative palettes like&nbsp;`"matrixpalette"` and `"c64palette"` are ignored. It can be convenient to keep extra unused alternatives in the file so that you can easily copy/paste the values or names of the palettes in order to change&nbsp; the active colors.

![Fruit Jam OS launcher with green and black color theme that is styled after The Matrix](https://cdn-learn.adafruit.com/assets/assets/000/139/103/medium800/circuitpython_launcher_matrix_palette.png?1755796650 Black and green color palette inspired by The Matrix)

## Favorite Apps

By default, the app icons in the launcher appear in alphabetical order by app title. The Fruit Jam OS launcher allows you to set a list of `"favorites"`&nbsp;within the **launcher.conf.json** file. The values in the list should be strings that match the names of the folders inside the **apps/** folder on the&nbsp; **CIRCUITPY** drive.

Here is an example&nbsp;`"favorites"` configuration that sets 6 specific apps to occupy the full 2x3 grid on the first page of the launcher.

```auto
"favorites": [
    "Fruit_Jam_IRC_Client",
    "Larsio_Paint_Music",
    "Metro_RP2350_Breakout",
    "Metro_RP2350_Minesweeper",
    "Metro_RP2350_Snake",
    "Fruit_Jam_PyPaint"
  ],
```

![Fruit Jam OS launcher with first page of app icons set by the favorites list](https://cdn-learn.adafruit.com/assets/assets/000/139/104/medium800/circuitpython_launcher_favorites.png?1755799791 )

## Disable Mouse

The **launcher.conf.json** also supports a way to disable the mouse. This can be useful if you have a combination USB keyboard/mouse device plugged in and want to ensure that the keyboard is used by the launcher instead of the mouse. CircuitPython does not currently support using both at the same time on a combo device. Set the `"use_mouse"` key in **launcher.conf.json** to `false` in order to disable the mouse support in the launcher.

```auto
"use_mouse": false,
```

# Fruit Jam OS

## Editor

![Fruit Jam OS editor with the Snake game code.py file open.](https://cdn-learn.adafruit.com/assets/assets/000/139/105/medium800/circuitpython_fruit_jam_os_editor.png?1755800046 )

Fruit Jam OS features a built-in Editor app which allows you to view and edit code and other text based files on the Fruit Jam's drive. The Fruit Jam OS Editor is loosely inspired by [GNU Nano](https://en.wikipedia.org/wiki/GNU_nano) but does not support all of the same features or hotkeys.&nbsp;

To edit the **code.py** for a specific app, choose the app in the launcher and then press the **E** key. To open any arbitrary file, choose the Editor app icon and press Enter. When you launch the Editor by its icon, it will open a file chooser that lets you select a file to open from the&nbsp; **CIRCUITPY** drive.

Along the bottom of the editor is a system bar which has inverse coloring from the rest of the editor space. This bar shows the currently open file, the drive mount state ( **RO** for readonly or **RW** for read/write), hotkey reminders for the available actions, and in the bottom right, the current **x** , **y** position of the cursor.

## Navigation & Usage

The primary navigation and control within the Editor is done with a USB keyboard. Use arrow keys to move the cursor around the screen. Type letters, numbers or characters to write into the file at the cursor's location. There are a number of Ctrl+[Key] hotkeys available as well:

- **Ctrl+W** - Toggle the readonly state of the drive. By default in CircuitPython the drive is mounted read-only so the editor will be unable to save modifications to files. Pressing **Ctrl+W** will reboot the Fruit Jam with the drive mounted writeable, and launch back into the Editor with the same file open so that you can make edits and save them. Pressing **Ctrl+W** again would then reboot and toggle back to readonly. See the [Storage page](https://learn.adafruit.com/circuitpython-essentials/circuitpython-storage) in the CircuitPython essentials guide for details on storage mounting. See the [Boot Sequence page](https://learn.adafruit.com/fruit-jam-os/boot-sequence) in this guide for details on how Fruit Jam OS facilitates the toggling of readonly mounting.
- **Ctrl+R** - Run the current CircuitPython code file. This will also set up arguments for the launcher that will cause it to automatically launch back into the editor with the current code file the next time the launcher is run. So the app will launch, and then when it finishes or exits by the user, the Editor will open back up showing the same file. This makes a iteratively developing a CircuitPython script more convenient.
- **Ctrl+O** - Open a new file. This will show a file chooser which may be navigated with up/down arrow keys. Press Enter to open whichever file is currently selected.
- **Ctrl+F** - Find some text within the file. Pressing **Ctrl+F** will temporarily change the system bar to an input so you can type in a string to search for. When you press Enter, the file will be searched for the input string and, if found, the cursor will move to the next instance of that string within the file.
- **Ctrl+G** - Go to line number. Pressing **Ctrl+G** will temporarily change the system bar to an input for the user to type a number into. When you press Enter the cursor will move to the line number you gave.
- **Ctrl+C** - Quit the editor. Pressing **Ctrl+C** will exit out of the editor app and go back to the launcher.

The next two hotkeys are only available if the storage drive is currently mounted writable. They are not available when the drive is read-only.

- **Ctrl+S** - Save the current file to the drive.
- **Ctrl+X** - Save the current file to the drive, and exit the editor app.

## Optional Mouse

If you have both a USB keyboard and a USB mouse connected to the Fruit Jam, then the mouse can be used to move the cursor within the Editor. Move the mouse pointer to where you want the cursor and then left-click.

# Fruit Jam OS

## Apps

![Fruit Jam OS launcher showing a selection of app icons.](https://cdn-learn.adafruit.com/assets/assets/000/139/106/medium800/circuitpython_launcher_favorites.png?1755802903 )

Apps in Fruit Jam OS are self-contained CircuitPython code projects that are stored inside of folders in the **apps/** folder on the **CIRCUITPY** drive. When you run an app by clicking or pressing Enter on it in the launcher, it is run using the [`supervisor.set_next_code_file()`](https://docs.circuitpython.org/en/latest/shared-bindings/supervisor/index.html#supervisor.set_next_code_file) function.

## Adding Apps On Your Own Device

To add your own custom app, simply put the **code.py** and any assets (data files) for it inside a folder, and then put that folder inside of the **apps/** folder. You may optionally add a **metadata.json** and icon image file inside of the directory to control the title and icon that will be used for your app in the launcher.

**metadata.json** can contain the keys `"title"` and `"icon"`, which hold string values representing the title and icon file to show for the app in the launcher grid. Here is an example of the metadata file for a custom app:

```auto
{
  "title": "CustomApp",
  "icon": "icon.bmp"
}
```

At a minimum, your custom app folder must contain a **code.py** file. It is recommended to also have **metadata.json** and **icon.bmp** files as well, but default values for the title and icon will be used if they are absent so they are not strictly required.

Any other assets the app needs, like images, audio, or other files, should also be put inside of this directory. You can also nest further folders inside of this one if your app is large and you want to organize its code and assets more. But the **code.py** file must exist at the top level in your **app/** folder.

![Files for a custom app inside of Fruit Jam OS.](https://cdn-learn.adafruit.com/assets/assets/000/139/107/medium640/circuitpython_custom_app_files.png?1755803708)

![Fruit Jam OS launcher with the example custom app icon and title showing.](https://cdn-learn.adafruit.com/assets/assets/000/139/108/medium640/circuitpython_custom_app_launcher.png?1755803771)

## Included Apps

Aside from the Editor, there are several apps and games that come included with Fruit Jam OS. Here is a list of all included apps as of Fruit Jam OS version 1.0.13

- [IRC Client](https://learn.adafruit.com/fruit-jam-irc-client-in-circuitpython)
- [Larsio Paint](https://learn.adafruit.com/larsio-paint-music)
- [PyBasic](https://github.com/adafruit/Fruit-Jam-OS/tree/main/builtin_apps/PyBasic)
- [PyDOS](https://github.com/adafruit/Fruit-Jam-OS/tree/main/builtin_apps/PyDOS)
- [Chip's Challenge](https://learn.adafruit.com/256-color-gaming-on-the-metro-rp2350)
- [Minesweeper](https://learn.adafruit.com/minesweeper-on-metro-rp2350)
- [The Matrix Rain](https://learn.adafruit.com/return-to-the-matrix-with-the-metro-rp2350/circuitpython-version)
- [Memory Game](https://learn.adafruit.com/create-a-memory-game-on-metro-rp2350)
- [Match3 Game](https://learn.adafruit.com/match3-game-on-metro-rp2350)
- [PyPaint](https://github.com/adafruit/Adafruit_Learning_System_Guides/tree/main/Fruit_Jam/Fruit_Jam_PyPaint)
- [Flappy Nyan Cat](https://learn.adafruit.com/flappy-nyan-cat-game-on-metro-rp2350)
- [Snake Game](https://learn.adafruit.com/snake-game-on-metro-rp2350)
- [Breakout Game](https://learn.adafruit.com/breakout-game-on-metro-rp2350-and-fruit-jam)
- [Spell Jam](https://learn.adafruit.com/spell-jam-app-on-fruit-jam)
- [Logic Gates Simulator](https://learn.adafruit.com/logic-gates-simulator-on-fruit-jam)

Many of the included apps were originally created as Metro RP2350 projects for other Learn Guides.

## Submit An App For Inclusion In Fruit Jam OS

We welcome Learn Guide authors and community members to submit a apps for consideration to be included in Fruit Jam OS. Depending on whether or not there will be a Learn Guide for the project or not, the process will be slightly different.&nbsp;

### Learn Authors

If there will be an Adafruit Learn Guide for the app that you are adding, then your app source code can be submitted in a pull request (PR) to the [Adafruit\_Learning\_System\_Guides](https://github.com/adafruit/Adafruit_Learning_System_Guides/) repository on GitHub as usual. Once project code is merged into that repository, the next step is to submit a PR to the [Fruit Jam OS repository](https://github.com/adafruit/Fruit-Jam-OS/pulls)&nbsp;adding the new app to the list of apps in the [build script here](https://github.com/adafruit/Fruit-Jam-OS/blob/main/build.py#L11). To add a new app you need to create a new tuple in the list. For example:

```auto
LEARN_PROJECT_PATHS = [
    ...
    ("Fruit_Jam/Awesome_New_App/","Awesome_New_App"),
]
```

The tuple contains the path within the Learning System Guides repository to the new app, and a name to use for the folder when the app gets copied into the **apps/** folder during the Fruit Jam OS build process. Often this will be the same name as the folder that your project is located in, as in the example above with&nbsp;`"Awesome_New_App"`, but the names can differ depending on the structure of the project in the Learn repository.

## Community Members

If there is not going to be a Learn Guide for your app, you may submit a single PR directly to the [Fruit Jam OS repo](https://github.com/adafruit/Fruit-Jam-OS/pulls) adding your app directory into the **builtin\_apps/** [folder within that repo](https://github.com/adafruit/Fruit-Jam-OS/tree/main/builtin_apps). For apps in the **builtin\_apps/,** there is no need to include them in the `LEARN_PROJECT_PATHS` list. Simply existing inside of **builtin\_apps/** is enough for the build script to include them in during the building process.

# Fruit Jam OS

## Screensavers

![Adafruit Fruit Jam displaying the flying toasters screensaver on a mini display](https://cdn-learn.adafruit.com/assets/assets/000/141/107/medium640/raspberry_pi_flying_toasters.jpg?1762977489 )

![Adafruit Fruit Jam displaying the fish tank screensaver on a mini display](https://cdn-learn.adafruit.com/assets/assets/000/141/108/medium640/raspberry_pi_fish_tank.jpg?1762977504 )

![Adafruit Fruit Jam displaying the bouncing logo screensaver on a mini display](https://cdn-learn.adafruit.com/assets/assets/000/141/109/medium640/raspberry_pi_bouncing_logo.jpg?1762977522 )

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.

![Fruit Jam OS launcher with the ScreenSave app selected.](https://cdn-learn.adafruit.com/assets/assets/000/141/894/medium640/raspberry_pi_ScreenSave_launcher_icon.png?1768316222)

![Fruit Jam OS ScreenSave app with flying toasters preview.](https://cdn-learn.adafruit.com/assets/assets/000/141/895/medium640/raspberry_pi_ScreenSave_app.png?1768316248)

## Launcher Config File

Add a&nbsp;`"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&nbsp;`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**.

```javascript
{
  "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.

### Flying Toasters
This is one of the classic screensavers from [After Dark](https://en.wikipedia.org/wiki/After_Dark_(software)). 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.

![Flying Toasters screensaver with winged toasters and pieces of toast flying across the display](https://cdn-learn.adafruit.com/assets/assets/000/141/106/medium640thumb/raspberry_pi_toasters.jpg?1762973258)

```javascript
"screensaver": {
	"module": "/apps/Screensavers/flying_toasters_screensaver"
},
"screensaver.background_color": "transparent"
```

### Fish Tank
This is another favorite from [After Dark](https://en.wikipedia.org/wiki/After_Dark_(software)). 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.

![Fish tank screensaver with different kinds of fish swimming back and forth across a dark screen](https://cdn-learn.adafruit.com/assets/assets/000/141/105/medium640thumb/raspberry_pi_fish.jpg?1762973198)

```javascript
"screensaver": {
	"module": "/apps/Screensavers/fish_screensaver"
},
"screensaver.background_color": "0x001122"
```

### Bouncing Logo
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.

![Bouncing Fruit Jam logo screensaver](https://cdn-learn.adafruit.com/assets/assets/000/141/104/medium640thumb/raspberry_pi_logo.jpg?1762973108)

```auto
"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.&nbsp;

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.

```javascript
"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&nbsp; **/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.

```javascript
"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&nbsp;`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.

```javascript
"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&nbsp;[built-in screensavers](https://github.com/adafruit/Fruit-Jam-OS/tree/main/builtin_apps/Screensavers) as needed while creating your own.

https://github.com/adafruit/Fruit-Jam-OS/blob/main/builtin_apps/Screensavers/bouncing_logo_screensaver.py


## Featured Products

### Adafruit Fruit Jam - Mini RP2350 Computer

[Adafruit Fruit Jam - Mini RP2350 Computer](https://www.adafruit.com/product/6200)
We were catching up on a recent [hackaday hackchat with eben upton](https://hackaday.io/event/202122-raspberry-pi-hack-chat-with-eben-upton)&nbsp;and learned some fun facts: such as the DVI hack for the RP2040 was inspired by <a...></a...>

Out of Stock
[Buy Now](https://www.adafruit.com/product/6200)
[Related Guides to the Product](https://learn.adafruit.com/products/6200/guides)
### Mini Chiclet Keyboard - USB Wired - Black

[Mini Chiclet Keyboard - USB Wired - Black](https://www.adafruit.com/product/1736)
Add a good quality, slim keyboard to your&nbsp;Raspberry Pi, Beagle Bone Black, or other single-board-computer with this sleek black chiclet keyboard. It's a full QWERTY keyboard with a USB cable and is compatible with all operating systems. We tried many keyboards to find one that felt...

In Stock
[Buy Now](https://www.adafruit.com/product/1736)
[Related Guides to the Product](https://learn.adafruit.com/products/1736/guides)
### USB Wired Mouse - Two Buttons plus Wheel

[USB Wired Mouse - Two Buttons plus Wheel](https://www.adafruit.com/product/2025)
This is a mouse. &nbsp;A nice, simple mouse. &nbsp;No bells or whistles. &nbsp;Just a mouse.  
  
But that doesn't mean it's not the best simple mouse!&nbsp; We compared a few and liked this one quite a bit. &nbsp;It's optical for good resolution and precision, has two...

In Stock
[Buy Now](https://www.adafruit.com/product/2025)
[Related Guides to the Product](https://learn.adafruit.com/products/2025/guides)
### HDMI Cable - 1 meter

[HDMI Cable - 1 meter](https://www.adafruit.com/product/608)
Connect two HDMI devices together with this basic HDMI cable. It has nice molded grips for easy installation, and is 1 meter long (about 3 feet). This is a HDMI 1.3 cable.

We're now stocking a very fancy Official Raspberry Pi cable with overmolding and a Pi logo. Please note...

In Stock
[Buy Now](https://www.adafruit.com/product/608)
[Related Guides to the Product](https://learn.adafruit.com/products/608/guides)
### USB Type A to Type C Cable - approx 1 meter / 3 ft long

[USB Type A to Type C Cable - approx 1 meter / 3 ft long](https://www.adafruit.com/product/4474)
As technology changes and adapts, so does Adafruit. This&nbsp;&nbsp; **USB Type A to Type C** cable will help you with the transition to USB C, even if you're still totin' around a USB Type A hub, computer or laptop.

USB C is the latest industry-standard connector for...

In Stock
[Buy Now](https://www.adafruit.com/product/4474)
[Related Guides to the Product](https://learn.adafruit.com/products/4474/guides)
### 7" Display 1280x800 (720p) IPS + Speakers - HDMI/VGA/NTSC/PAL

[7" Display 1280x800 (720p) IPS + Speakers - HDMI/VGA/NTSC/PAL](https://www.adafruit.com/product/1667)
Yes, this is an adorable small HDMI television with incredibly high resolution **and built in 3W stereo speakers**! We tried to get the smallest possible HDMI/VGA display with high-res, high-contrast visibility. The visible display measures only 7" (17.8cm) diagonal, and the TFT comes...

In Stock
[Buy Now](https://www.adafruit.com/product/1667)
[Related Guides to the Product](https://learn.adafruit.com/products/1667/guides)

## Related Guides

- [Using a Mouse with USB Host](https://learn.adafruit.com/using-a-mouse-with-usb-host.md)
- [Using a Keyboard with USB Host](https://learn.adafruit.com/using-a-keyboard-with-usb-host.md)
- [Adafruit Fruit Jam](https://learn.adafruit.com/adafruit-fruit-jam.md)
- [Pi Video Output Using pygame](https://learn.adafruit.com/pi-video-output-using-pygame.md)
- [Feather RP2350 Audio Reactive Video Synth](https://learn.adafruit.com/feather-rp2350-audio-reactive-video-synth.md)
- [Python Virtual Environment Usage on Raspberry Pi](https://learn.adafruit.com/python-virtual-environment-usage-on-raspberry-pi.md)
- [PyPaint Drawing Program In CircuitPython](https://learn.adafruit.com/pypaint.md)
- [Building CircuitPython](https://learn.adafruit.com/building-circuitpython.md)
- [Clue Coffee Scale](https://learn.adafruit.com/clue-coffee-scale.md)
- [Twin Peaks Light Reactive Picture Frame](https://learn.adafruit.com/twin-peaks-light-reactive-pyportal-picture-frame.md)
- [Wireless Dual Stepper Control with Adafruit IO, Raspberry Pi and Python](https://learn.adafruit.com/wireless-stepper-control-with-adafruit-io-circuitpython-raspberry-pi-python.md)
- [Bluetooth CLUE Robot Car using CircuitPython](https://learn.adafruit.com/bluetooth-clue-robot-car-using-circuitpython.md)
- [Paper Craft Zoetrope with Crickit](https://learn.adafruit.com/paper-craft-zoetrope-with-circuit-python.md)
- [Introducing Adafruit PyGamer](https://learn.adafruit.com/adafruit-pygamer.md)
- [Using Piezo Buzzers with CircuitPython & Arduino](https://learn.adafruit.com/using-piezo-buzzers-with-circuitpython-arduino.md)
- [Adafruit STEMMA Audio Amp](https://learn.adafruit.com/stemma-audio-amp.md)
- [Bare E-Ink Displays Crash Course](https://learn.adafruit.com/bare-e-ink-displays-crash-course.md)
- [Adafruit TMC2209 Stepper Motor Driver Breakout Board](https://learn.adafruit.com/adafruit-tmc2209-stepper-motor-driver-breakout-board.md)
