# RoseWish: a Pygame visual novel built as a personal gift

> RoseWish is a small Python pixel art narrative game with a configurable script, a state machine, a particle system and audio, packaged so a person can personalise it and hand it to someone else. It suits readers who want a worked example of decoupled game architecture, and it is a one-off story rather than a reusable engine.

**AhmadHassan-BTed/RoseWish** — A heartfelt, interactive narrative mini-game built in Python for Rose Day. Features custom entities, a dynamic dialogue system, animated particle effects, and integrated audio to deliver a unique, romantic digital experience.

- Repository: https://github.com/AhmadHassan-BTed/RoseWish
- Stars: 2,843 · Forks: 0
- Language: Python
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/ahmadhassan-bted-rosewish

## A gift, not a game engine

RoseWish is a narrative mini-game written in Python for Rose Day, and the README is explicit about its purpose in a way most project descriptions are not. It was crafted as a heartfelt way to express love, and the instruction is to use it to wish someone a Happy Rose Day, customise it with private memories, and let the pixel art do the rest.

That framing matters for how you read the rest of the documentation, because a project built as a personal gift is a different kind of artefact from a library. The two characters are named MrLover and MissLovely, and the narrative is a single day that runs from dreams, to napping, to a heartfelt surprise. The .env template makes this concrete: the file has PLAYER_NAME, PARTNER_NAME and PARTNER_NICKNAME, a set of message strings for the introduction, the meeting, the greeting, the reply, the reveal and a marriage message, plus window title, dimensions, FPS, the music path, the volume, and the main and sub titles.

The project states its own motivation: it was built to demonstrate clean engineering practices in game development while providing a meaningful, personalised gift experience. So the architecture is the actual subject of the repository, and the story is the payload that keeps the architecture honest. If you are looking for something to reuse, this is a well documented sample rather than a tool. If you are looking for something to give to a person, the .env file is the entire customisation surface.

## A service registry, a state machine and three game systems

The architecture section describes a decoupled structure with high cohesion and minimal coupling between systems, and the workflow diagram shows how the pieces connect.

main.py hands off to a GameEngine, and the GameEngine holds two things: a service registry and a state machine. The registry resolves an AudioService and a RenderService, which sit in a services layer. The state machine drives three game systems, a narrative director, a particle manager and a dialogue system, and the narrative director in turn owns two entities, the MrLover and MissLovely characters.

The class diagram adds the internal relationships. GameEngine exposes run(), update(dt) and render(). Character provides update(dt) and draw(screen), and MissLovely extends it with draw_sleeping() and draw_standing(), while MrLover extends it with a holding_rose boolean. The GameEngine composes the ParticleManager, the DialogueBox and the Background.

Two details in that diagram carry more design weight than the rest. The composition of the particle manager, dialogue box and background into the engine, rather than their inheritance, means each of those is replaceable without touching the engine. And the way the character subclasses differ only in drawing, with the shared behaviour in the base class, is the kind of small inheritance that stays readable. The dependency injection in core/ and the event bus live alongside it, and the services layer is described as decoupled audio and rendering services, which is what lets the same game logic run against a different renderer.

## The repository layout, and the packages the manifest does not list

The documented repository structure is short enough to take in at a glance. The src/ directory is split into core for dependency injection and the event bus, engine for the main game loop and state management, entities for character logic and pixel art rendering, services for the decoupled audio and rendering services, ui for backgrounds and dialogue overlays, utils for particle systems and constants, config for environment based configuration, and main.py as the application entry point. Alongside it are a docs/ directory of technical specifications, an.env.example template, a pyproject.toml and a requirements.txt.

The package list in the build configuration is where the interesting discrepancy is. The setuptools packages list is src, src.config, src.core, src.engine, src.entities, src.services, src.story, src.ui, src.utils and src.world. The documented structure mentions eight of those directories and omits src.story and src.world, while the manifest lists ten packages in total.

That gap is a small thing and it points at a real one. The narrative in this project is a state machine driving a narrative director, and a src.story package and a src.world package suggest the story content and the world model are separated from the systems that play them, which is exactly the split you would want if the content were data rather than code. The documentation is a summary rather than a complete map of the tree, and the source is the authority.

The project also carries the usual support files, a CHANGELOG.md, CODE_OF_CONDUCT.md, CONTRIBUTING.md, ROADMAP.md, SECURITY.md, SUPPORT.md, a Makefile, a Dockerfile, pyrightconfig.json and a ruff.json with a ruff_errors.txt alongside it.

## Running it: install, edit the .env file, launch

The quick start is short. The prerequisites are Python 3.12 or higher and the pip package manager, and the install is a clone followed by a dependency install:

```bash
# Clone the repository
git clone https://github.com/AhmadHassan-BTed/Rose-Day-Wishing-Game.git
cd Rose-Day-Wishing-Game

# Install dependencies
pip install -r requirements.txt
```

The requirements file has two entries, pygame at 2.5.0 or newer and python-dotenv at 1.0.0 or newer, and the build configuration lists the same two. The configuration step is where the personalisation happens, and the.env file is pre-populated with generic values that you replace:

```bash
# Open .env and change names/messages
# Example: PLAYER_NAME="Your Name"
```

Then you launch it:

```bash
python src/main.py
```

The data flow section describes the lifecycle in four stages. The GameEngine initialises services and registers them in the central Registry. Settings are loaded from.env and validated through the config module. The execution loop then handles input with events captured through pygame, updates systems based on delta time so movement is frame independent, and renders through the RenderService, which composites the background, the entities and the UI. Shutdown is a clean termination of the Pygame mixer and the display.

The delta time detail is the one that shows the author knew what they were doing, since an update that ignores elapsed time would make the particle motion and the character animation run at different speeds depending on the display.

## Version requirements disagree across the Dockerfile, the metadata and the README

Three sources give three different Python versions, and picking the wrong one will cost you an afternoon.

The quick start asks for Python 3.12 or higher, and the badge at the top of the README says Python 3.12. The build metadata says requires-python is greater than or equal to 3.8, the classifiers list only Programming Language :: Python :: 3 with no specific minor version, and the ruff configuration sets target-version to py38 with a line length of 100. The container image is built on python:3.9-slim.

So the strictest statement is the README, and the loosest is the metadata. Since the metadata is what pip uses to decide whether a wheel can be installed, declaring 3.8 support while the documentation asks for 3.12 means the package will install on 3.8 and then may fail at runtime.

The container file has its own lesson. It installs the system libraries Pygame needs, including python3-dev, the SDL2 development packages for image, mixer and text, libfreetype, libportmidi, libavformat, libswscale, libjpeg and libpng, then runs pip install --no-cache-dir . and sets the command to python src/main.py. The comment next to that command is worth quoting for its honesty: the command to run the game will fail without a display.

That is the whole warning about running this in a container. The image gives you a Linux environment with the graphics libraries present, but Pygame needs an X server or a framebuffer, so the container is a way to get the dependencies right, not a way to play the game.

## Particles, audio and the choice of Pygame

The feature list names four things: a multi-stage state machine guiding the two characters through their day, hand-crafted pixel art backgrounds that shift from the warmth of the sun to the mystery of the evening, a particle system described as a high-performance physics engine filling the air with drifting snow, floating hearts and rose petals, and integrated audio services for a continuous musical journey.

The particles are the part that would be the most work in another stack, and the choice of Pygame for it is the reason this project is short. Pygame ships with particle-friendly primitives and a mixer, and the project leans on that. The configuration exposes a MUSIC_PATH pointing at an MP3 and a VOLUME of 0.5, and the shutdown step explicitly terminates the Pygame mixer, which means the audio is a first class part of the runtime rather than a decoration.

The backgrounds are described as hand-crafted pixel art, and the screenshots in the assets directory are the evidence. The scenes progress through the day, which is also the narrative structure, so the art and the state machine are doing the same job from two directions.

The credits name the Pygame community, the licence is MIT, and the author is Ahmad Hassan, also credited as B-Ted. There are no GitHub releases, and the last push to the main branch was on 2026-07-06, so the project is not being updated on a schedule. For a gift that is finished and handed over, that is fine, but anyone planning to extend it should expect to maintain it themselves.

## Conclusion

Adopt RoseWish as a reference if you want to read a small game that separates its engine, services, entities and story data cleanly, since the module layout and the state machine are laid out plainly in the documentation. Do not adopt it as an engine for your own game, because the story, the character names and the art are one authored piece, not a framework with pluggable content. Before you run it, decide whether you have a display, because the container image notes that the launch command fails without one, and check the Python version requirement, since the quick start asks for 3.12 while the package metadata declares support from 3.8 and the container image uses 3.9.

## FAQ

### How do I run RoseWish?

Clone the repository, run `pip install -r requirements.txt`, then launch with `python src/main.py`. The quick start asks for Python 3.12 or higher and the pip package manager, and the runtime dependencies are pygame and python-dotenv.

### How do I personalise the RoseWish game?

Edit the .env file, which is pre-configured with generic values. It holds PLAYER_NAME, PARTNER_NAME, PARTNER_NICKNAME, the message strings for the intro, meeting, greeting, reply, reveal and marriage, the window title and dimensions, FPS, MUSIC_PATH, VOLUME and the main and sub titles.

### Does RoseWish work in Docker?

The image installs the SDL2 and other system libraries Pygame needs, but the launch command in the Dockerfile is marked as failing without a display. The container gives you the dependencies, not a headless game, so you still need a display or a framebuffer to play it.

### What is the architecture of the RoseWish codebase?

A GameEngine holds a service registry for the audio and render services and a state machine driving a narrative director, a particle manager and a dialogue system. The source is split into core, engine, entities, services, ui, utils and config directories, and the build configuration also lists src.story and src.world packages.

## Sources

- [AhmadHassan-BTed/RoseWish on GitHub](https://github.com/AhmadHassan-BTed/RoseWish)
- [Issues](https://github.com/AhmadHassan-BTed/RoseWish/issues)
- [License: MIT](https://github.com/AhmadHassan-BTed/RoseWish/blob/main/LICENSE)
- [README](https://github.com/AhmadHassan-BTed/RoseWish/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ahmadhassan-bted-rosewish
