Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions badge/apps/fireplace/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# 🔥 Fireplace

A cosy animated fireplace app for the GitHub Universe 2025 badge. The speed can be adjusted to the user's preference.

<img src="assets/fireplace_badge.jpg" width="30%">

This app was inspired by the fireplace from [Lenny's Podcast](https://www.lennysnewsletter.com/podcast) quietly running in the background.

<img src="assets/lenny_fireplace.jpg">

## Controls

| Button | Action |
|--------|--------|
| **↑ UP** | Speed up (−50ms per press, min 50ms/frame) |
| **↓ DOWN** | Slow down (+50ms per press, max 1000ms/frame) |
| **A / B / C** | Reset to default speed |
| **HOME** | Return to menu |

The current frame duration is displayed briefly at the bottom of the screen whenever the speed is changed.

## Installation

Copy the `fireplace/` folder to `/system/apps/fireplace/` on your badge (put it into disk mode first by double-pressing RESET while connected via USB-C).

```
fireplace/
├── __init__.py # App code
├── icon.png # Menu icon (24x24)
├── assets/ # Source images
│ ├── fireplace.gif # Original source GIF
│ ├── fireplace_badge.jpg # Badge photo
│ └── lenny_fireplace.jpg # Lenny photo
└── frames/ # Extracted PNG frames (frame_0000.png … frame_0019.png)
```

## Running in the Simulator

```bash
python simulator/badge_simulator.py badge/apps/fireplace -C badge --scale 4
```

## Animation Details

- **Source**: [Tenor GIF](https://tenor.com/en-CA/view/seninle-a%C5%9Fkom-yalanmo%C5%9F-gif-27389050)
- **Frames**: 20 PNGs at 160×120 pixels
- **Default speed**: 100ms per frame (10 fps)
83 changes: 83 additions & 0 deletions badge/apps/fireplace/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import sys
import os

sys.path.insert(0, "/system/apps/fireplace")
os.chdir("/system/apps/fireplace")

from badgeware import screen, io, run, brushes, PixelFont, shapes

FRAME_COUNT = 20
DEFAULT_DURATION = 100 # ms per frame
MIN_DURATION = 50
MAX_DURATION = 1000
SPEED_STEP = 50
LABEL_TIMEOUT = 1500 # ms to show the label after a speed change

_current_frame = 0
_last_tick = None
_frame_duration = DEFAULT_DURATION
_label_until = 0 # ticks timestamp until which to show the label
_needs_redraw = True # reload frame when it advances or label expires

_font = None
_label_brush = None
_bg_brush = None


def init():
global _font, _label_brush, _bg_brush
_font = PixelFont.load("/system/assets/fonts/nope.ppf")
screen.font = _font
_label_brush = brushes.color(255, 255, 255, 200)
_bg_brush = brushes.color(0, 0, 0, 150)


def update():
global _current_frame, _last_tick, _frame_duration, _label_until, _needs_redraw

if _last_tick is None:
_last_tick = io.ticks

# Speed up
if io.BUTTON_UP in io.pressed:
_frame_duration = max(MIN_DURATION, _frame_duration - SPEED_STEP)
_label_until = io.ticks + LABEL_TIMEOUT

# Slow down
if io.BUTTON_DOWN in io.pressed:
_frame_duration = min(MAX_DURATION, _frame_duration + SPEED_STEP)
_label_until = io.ticks + LABEL_TIMEOUT

# Any of A, B, C resets to default
if io.BUTTON_A in io.pressed or io.BUTTON_B in io.pressed or io.BUTTON_C in io.pressed:
_frame_duration = DEFAULT_DURATION
_label_until = io.ticks + LABEL_TIMEOUT

# Advance frame
if io.ticks - _last_tick >= _frame_duration:
_current_frame = (_current_frame + 1) % FRAME_COUNT
_last_tick = io.ticks
_needs_redraw = True

showing_label = io.ticks < _label_until

# Only reload the PNG when the frame changed or the label just cleared
if _needs_redraw:
screen.load_into(f"frames/frame_{_current_frame:04d}.png")
_needs_redraw = showing_label # stay dirty while label is visible

# Show speed label if recently changed
if showing_label:
label = f"{_frame_duration}ms/frame"
w, h = screen.measure_text(label)
pad = 4
x = (screen.width - w) // 2
y = screen.height - h - pad * 2
screen.brush = _bg_brush
screen.draw(shapes.rectangle(x - pad, y - pad, w + pad * 2, h + pad * 2))
screen.brush = _label_brush
screen.text(label, x, y)


if __name__ == "__main__":
run(update, init=init)
Binary file added badge/apps/fireplace/assets/fireplace.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/assets/fireplace_badge.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0000.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0002.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0003.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0004.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0005.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0006.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0007.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0008.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0009.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0010.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0011.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0012.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0013.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0014.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0015.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0016.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0017.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0018.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/frames/frame_0019.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added badge/apps/fireplace/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.