Project Info
Inspiration
We've seen many recent trends, like looksmaxxing, and have realized that they often encourage harmful behavior. We believe the solution is to foster open conversation and break down the stigma surrounding these topics, thereby promoting healthy decisions. When people can get together and feel comfortable sharing their struggles, they can find support and encouragement from those they value and whose opinions matter. What better way to break the ice than with a party game?
What it does
Moggie is a portable AI party-game kiosk running on a Raspberry Pi 5 with QNX. Players stand in front of the camera and compete in fast physical and facial-expression mini-games, including hand-motion challenges, face mirroring, and emoji expression matching. The games can be understood instantly, leading to quick, accessible, and fun viral gameplay. Moggie lets people bond over the latest trends and socialize rather than isolate, helping address a major factor in the mental health issues and stigma associated with these internet phenomena. On a more technical level, we are running pygame on a Raspberry Pi 5, very generously provided by QNX, along with their real-time, microkernel-architecture operating system designed to handle time-sensitive applications. We wrote a custom camera driver from scratch to enable the provided camera to connect with our pygame pipeline. Each frame is passed through MediaPipe to produce body landmarks and geometry detection. Results are then timestamped and polled by the game frame by frame. A SQLite database stores per-game sessions and keeps track of the top scores in a leaderboard. Moggie is made to be shareable. Innately, it leads to viral shareable clips as the games are trendy and instant. Similar to other viral games, players get a ready-to-share clip after a MOGGIE session. Hit a high score or make a smart play? Pika + MOGGIE backend has a clip ready for your social media.
How we built it
We brainstormed extensively as a team, then drafted up a design document with LLM tooling. We mainly used Codex 5.5 for most of the code implementation while focusing on what human brains still do best: ideation and creativity. We used our complimentary Claude credits to build the most complicated part of our application: the camera driver. We spent our time making UI/UX design choices, identifying ways to solve problems we encountered during implementation, and ensuring our project remained cohesive as multiple developers worked in parallel. The QNX camera path was the deepest systems work. We configured the QNX Sensor Framework for the Raspberry Pi Camera Module 3 / IMX708 stack, then wrote moggi_camgrab, a small C program that uses CamAPI’s read-only viewfinder path to receive NV12 frames. The grabber emits frames through a custom lightweight MGF1 wire format. A Python backend reads the stream on a background thread, keeps only the newest frame to avoid latency buildup, converts NV12 to BGR with OpenCV, and hands frames to the Pygame game screens. We also optimized the game around the Pi’s constraints. For example, we disable face tracking during the hand-motion game, use a faster, lightweight hand-motion fallback where needed, decimate camera frames in native code, and keep scoring/rendering independent from slower CV updates.
Challenges we ran into
One of the main goals of our product is to keep it as lightweight and performant as possible; thus, we opted to test out the QNX operating system. However, because there was no existing camera functionality, we spent much of our time programming a C driver to enable our game to capture frames from the attached camera module. Additionally, the performance on a Pi is obviously not as powerful as on a MacBook Pro, but, because of our commitment to portability and affordability, we continuously iterated and optimized, like removing unnecessary face-tracking during a hand-movement-oriented game, to ensure that it still ran on the Pi.
Accomplishments we're proud of
We got a real Raspberry Pi Camera Module 3 feed running inside a Pygame game on QNX, a use case in uncharted territory for QNX. That required: Configuring the QNX Sensor Framework for the Pi 5 camera path Building a native CamAPI frame grabber in C Designing a tiny custom NV12 stream protocol Bridging native camera frames into Python/OpenCV/Pygame Running local hand and face CV on constrained hardware Tuning the game so rendering and scoring stay responsive even when CV is slower We are especially proud that Moggie is not just a web mockup. It is a real embedded kiosk running on sponsor hardware with a live camera, HDMI display, local CV, and persistent gameplay state. We are able to play CV games at near-60 fps! Also, Moggie auto-clips and generates fun UGC-ready videos using Pika to increase virality. Hit a clip in Moggie and share with your friends!
What we learned
By focusing on optimization, we can run compelling applications even on simple hardware. In an age when the answer to every problem seems to be throwing more compute or RAM at it, we proved that it's still possible to craft well-designed, performant software that maximizes hardware utilization and the onboard OS.
What's next
for moggie We plan on expanding moggie to include more games. Eventually, we plan on creating a custom container and peripherals to actually sell as a party game! You can take Moggie to your friend's house, fun parties, mixers, and more! It attracts attention instantly and creates fun shareable moments.
Moggie
Moggie is a native Python kiosk game for Raspberry Pi OS 64-bit Lite. It is designed to boot directly into a Pygame/SDL2 shell, use one USB webcam for local CV gameplay, persist scores in SQLite, and treat cloud AI integrations as optional asynchronous polish.
Local Development
Requirements:
- Python 3.10+
- A virtual environment
- Optional: Redis for leaderboard cache development
- Optional: webcam for camera smoke tests
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"
cp .env.example .env
python -m app.main
In development mode, python -m app.main opens the windowed native shell. Use python -m app.main --frames 3 for a short startup smoke test that exits cleanly.
Demo Fallback Presets
Preset files live in config_presets/ and can be used directly on a laptop or copied into /etc/moggie/moggie.env for the Pi systemd service.
./scripts/run_with_preset.sh cloud_disabled -- --frames 3
./scripts/run_with_preset.sh booth_safe
./scripts/run_with_preset.sh sixty_seven_solo
./scripts/run_with_preset.sh emoji_alternating
./scripts/run_with_preset.sh emoji_solo
cloud_disabled: turns off Redis, Midjourney, Pika/Fal, LLM labels, cloud expression validation, and generated media saving. Local camera gameplay and SQLite leaderboards still work.booth_safe: production fullscreen plus the cloud-disabled path and conservative 640x480 camera / 320x240 CV settings.sixty_seven_solo: reduces 67 Challenge to one player and two tracked hands.emoji_alternating: keeps Emoji Face Match as a two-player flow but detects one face at a time.emoji_solo: last-resort single-player Emoji Face Match.
Attract mode is enabled by default. After MOGGIE_IDLE_TIMEOUT_SECONDS on the home screen, the kiosk cycles game cards, top scores, and recent generated media when MOGGIE_SAVE_GENERATED_MEDIA=true.
Useful Scripts
./scripts/dev.sh
./scripts/init_db.sh
./scripts/smoke_test_camera.py
./scripts/auth_midjourney.py
./scripts/run_game.sh
./scripts/run_with_preset.sh booth_safe
Midjourney Setup
Mog Mirror can use Midjourney's MCP server for async caricatures when MOGGIE_ENABLE_IMAGE_GENERATION=true and MOGGIE_ENABLE_MIDJOURNEY=true. Run scripts/auth_midjourney.py during setup over SSH or an admin terminal, complete OAuth on a phone or laptop, and paste the final callback URL back into the script.
The script writes token state to MOGGIE_MIDJOURNEY_TOKEN_STORE, defaulting to ~/.config/moggie/midjourney_oauth.json, with 0600 permissions. The kiosk service later uses that token store without opening a browser. Missing or expired auth only fails the AI job; the local score reveal still completes.
Raspberry Pi Launch Notes
The primary target is Raspberry Pi OS 64-bit Lite with no desktop environment. The service unit in systemd/moggie.service launches:
python -m app.main
Install system dependencies with scripts/install_pi_lite_deps.sh, then install the service with scripts/install_systemd_service.sh. The installer renders /etc/systemd/system/moggie.service with the current clone path, the current virtualenv Python, and the invoking user/group.
Recommended Pi setup:
sudo apt-get update
sudo apt-get install -y git
sudo mkdir -p /opt
sudo chown "$USER":"$USER" /opt
git clone git@github.com:BeanyZoldyck/moggie.git /opt/moggie
cd /opt/moggie
./scripts/install_pi_lite_deps.sh
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"
./scripts/init_db.sh
./scripts/smoke_test_camera.py
./scripts/install_systemd_service.sh
sudo systemctl start moggie.service
Systemd reads /etc/moggie/moggie.env if present. The installer creates it from config_presets/booth_safe.env on first install. To switch demo mode:
sudo cp config_presets/cloud_disabled.env /etc/moggie/moggie.env
sudo systemctl restart moggie.service
Check service status and logs:
sudo systemctl status moggie.service
journalctl -u moggie.service -f
Camera Troubleshooting
The kiosk retries a missing camera every MOGGIE_CAMERA_RETRY_SECONDS and shows the diagnostic in the home preview. If a camera opens and then drops frames, Moggie keeps the last good frame and continues polling.
Use these checks before judging:
v4l2-ctl --list-devices
MOGGIE_CAMERA_INDEX=0 ./scripts/smoke_test_camera.py
MOGGIE_CAMERA_INDEX=1 ./scripts/smoke_test_camera.py
If the preview is blank, unplug/replug the webcam, rerun the smoke test with the discovered index, update /etc/moggie/moggie.env, and restart the service.
QNX Raspberry Pi Camera Module 3
On the QNX Raspberry Pi 5 image, use the QNX CamAPI backend instead of cv2.VideoCapture:
gcc native/moggi_camgrab.c -o moggi_camgrab -lcamapi
./moggi_camgrab
MOGGIE_CAMERA_BACKEND=qnx ./scripts/smoke_test_camera.py
MOGGIE_CAMERA_BACKEND=qnx python -m app.main
The helper streams NV12 frames from the CamAPI viewfinder into Python. Pygame display still needs to run on the Pi HDMI console.
Judging Day Runbook
- Boot the Pi and confirm the idle attract screen appears after the home screen sits idle.
- Run one Mog Mirror round and confirm scores land on the leaderboard.
- Run 10 consecutive 67 Challenge rounds from home to score reveal and back. If tracking drops or FPS is poor, copy
config_presets/sixty_seven_solo.envinto/etc/moggie/moggie.envand restart. - Run Emoji Face Match. If two-face scoring is unreliable, switch to
emoji_alternating.env; if that still fails, switch toemoji_solo.env. - If venue network or cloud auth is unstable, switch to
cloud_disabled.envorbooth_safe.env. The local demo path should still play and persist scores. - Keep
journalctl -u moggie.service -fopen on an SSH session during setup. During judging, leave the kiosk fullscreen.
Demo reset:
sudo systemctl stop moggie.service
rm -f data/moggie.sqlite
./scripts/init_db.sh
sudo systemctl start moggie.service
Generated media reset, when media saving has been enabled:
rm -rf media/*
Stress-test checklist:
- 10 back-to-back 67 Challenge rounds complete without a crash.
- 10 home -> game -> score reveal -> leaderboard -> home transitions complete without a crash.
- Camera unplug/replug shows a diagnostic, then recovers after restart or retry.
- Cloud-disabled preset completes all local games with Redis and cloud services unavailable.
- Text remains readable on 1080p HDMI from booth distance.
Project Layout
app/main.py: application entrypointapp/core/moggie_app.py: Pygame app loopapp/config.py: typed environment configurationapp/db.py: SQLite initializationapp/core/: event bus, game registry, session/screen managersapp/services/: camera, CV, leaderboard, storage, Redis, AI, sponsor integration boundariesapp/games/: game modulesapp/cv/: local CV helpers and heuristicsapp/ai/: cloud/mock AI client interfacesscripts/: local, Pi, systemd, DB, and camera utilitiestests/: foundation tests
Analysis
View
Metric
- 60
- 18
- 16
- 3
Figures cover GitHub contributors during the hackathon window. A co-authored commit counts in full for each author, so per-member totals add up to more than the whole-team figures.
Technology
- CIn code
- HTMLIn code
- PythonIn code
- RedisIn code
4 of 4 appear in the indexed code.
AI coding agents
No AI coding agent signals were found in this repository.
Detected from committed agent config files and commit authorship. Absence of a signal is not proof an agent was unused.
Codebase size
Source size
1.5 MB
Source files
166
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
BeanyZoldyck/moggie
210 files · 27.2 MB · @ b4f2364
Structure
Interface
89 files · 42%Screens, components and styles rendered to the user.
+3 moreApplication logic
12 files · 6%Domain rules, services and shared utilities.
Data & schema
5 files · 2%Schema definitions, migrations and data access.
Supporting
Layers are inferred from where files sit in the tree, not from reading the code. A project that names its directories unconventionally will read oddly here — open the file browser to check anything the diagram implies.
Languages
- Markdown60%
- Python34%
- HTML5%
- C0%
- Shell0%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
pyproject.toml
pypi · 10- boto3
- mediapipe
- opencv-python
- pygame
- redis
- requests
- requests-oauthlib
- sounddevice
- websocket-client
- +1 more
Declared in the repository’s manifests at the indexed commit. A declared package is not proof it is used, and runtime dependencies are listed first.
Feature verification
Attract mode / idle screen cyclingVerified
Attract mode is enabled by default; cycles game cards, top scores, and recent generated media after idle timeout
Claimed on readmemedium confidenceapp/ui/screens/idle_attract_screen.py— Dedicated idle attract screen module implements the described cycling behaviorapp/config.py— Config exposes idle timeout settings referenced by the README (MOGGIE_IDLE_TIMEOUT_SECONDS)
Demo fallback config presets (cloud_disabled, booth_safe, solo/alternating modes)Verified
Preset files for degraded/demo modes usable via scripts/run_with_preset.sh
Claimed on readmehigh confidenceconfig_presets/cloud_disabled.env— Preset env file exists matching README descriptionconfig_presets/booth_safe.env— Preset env file exists matching README descriptionscripts/run_with_preset.sh— Script to apply presets exists
Emoji expression matching mini-gameVerified
Emoji expression matching mini-game
Claimed on Devposthigh confidenceapp/games/emoji_face_match.py:41— EmojiFaceMatchGame with target expression evaluators (smile, surprised, tongue_out, wink) implements expression matching
Face mirroring mini-game (Mog Mirror)Verified
Face mirroring mini-game
Claimed on Devposthigh confidenceapp/games/mog_mirror.py:20— MogMirrorGame class with facial geometry scoring (score_aura, _facial_geometry_score) implements the face mirroring game
Hand-motion mini-game (67 Challenge)Verified
Hand-motion challenges mini-game
Claimed on Devposthigh confidenceapp/games/sixty_seven.py:1— SixtySevenGame class implements the hand-motion game logicapp/cv/sixty_seven_counter.py— Dedicated CV counter module supports the hand-motion game
MediaPipe body/face/hand landmark detectionVerified
Each frame is passed through MediaPipe to produce body landmarks and geometry detection
Claimed on Devposthigh confidenceapp/cv/face_detection.py:113— Uses mediapipe multi_face_landmarks results to build per-face landmark geometryapp/cv/hand_landmarks.py:52— HandLandmarkService imports and uses the mediapipe module for hand detection
Midjourney caricature generation (Mog Mirror)Verified
Mog Mirror can use Midjourney's MCP server for async caricatures
Claimed on readmemedium confidenceapp/ai/midjourney_mcp_client.py:215— MidjourneyMCPClient.generate_caricature implements the async caricature generation call over MCP with OAuth token handling
Pika-generated shareable clipsVerified
Pika + MOGGIE backend has a clip ready for your social media after a session
Claimed on Devpostmedium confidenceapp/ai/fal_pika_client.py:47— generate_video_from_image implements calling the fal.ai Pika video generation APIapp/ai/pika_mcp_client.py— Alternate Pika MCP client path existsapp/services/ai_job_service.py:77— AIJobService wires Pika (MCP or fal) clients into an async job pipeline triggered from gameplay results
Pygame kiosk shell on Raspberry Pi 5 / QNXVerified
Runs pygame on a Raspberry Pi 5 with QNX real-time OS
Claimed on Devpostmedium confidenceapp/core/moggie_app.py— Pygame application loop drives the kiosk shellapp/cv/mediapipe_compat.py:8— QNX-specific protobuf/env configuration branches (sys.platform.startswith('qnx')) show real QNX-targeted code paths, not just claims
QNX custom camera driver (CamAPI/NV12 to Python)Verified
Custom camera driver written from scratch in C using QNX CamAPI, streaming NV12 frames via a custom MGF1 wire format to a Python backend
Claimed on Devposthigh confidencenative/moggi_camgrab.c:13— C source implements CamAPI viewfinder capture and defines the MGF1 magic header wire format described in the claimapp/services/qnx_camera_backend.py:21— QnxCamera class launches moggi_camgrab as a subprocess, parses the MGF1 framed NV12 stream, and converts frames to BGR with OpenCV for the Python/Pygame pipeline
Redis leaderboard cache (optional)Verified
Optional Redis for leaderboard cache development
Claimed on readmehigh confidenceapp/services/redis_cache_service.py:16— RedisCacheService implements a real Redis connection wrapperapp/services/leaderboard_service.py:265— top_scores uses redis.zrevrange sorted-set reads when Redis cache is active, falling back to SQLite otherwise
SQLite database for sessions and leaderboardVerified
A SQLite database stores per-game sessions and keeps track of the top scores in a leaderboard
Claimed on Devposthigh confidenceapp/db.py:16— SQLite schema defines players, game_sessions, scores, and media_assets tables with an index for leaderboard queriesapp/services/leaderboard_service.py:153— record_score and top_scores methods implement leaderboard read/write against the DB
Systemd service for Pi kiosk bootVerified
Service unit boots the kiosk directly via systemd on the Pi
Claimed on readmemedium confidencesystemd/moggie.service— Systemd unit file existsscripts/install_systemd_service.sh— Installer script renders and installs the service, matching README instructions
Twitter/X social auto-postingCode-supported
Implied by 'shareable' virality features (not explicit in Devpost text but present in code) allowing posting recap clips to X
Claimed on readmelow confidenceapp/services/social_post_service.py:72— post_to_x method exists and composes/post captions, but this specific capability is not explicitly claimed in the Devpost/README text, so it is extra functionality found in code rather than a claim to verify against
Custom hardware container/peripherals product lineBlocked
Plans to create a custom container and peripherals to sell as a party game (future roadmap)
Claimed on Devposthigh confidence
An AI agent derived these features from the project’s Devpost page and readme, then searched the code for each one. Verified features are backed by cited code; claimed-only features had no supporting code, which is not by itself proof a feature is missing.
Export this project's context (description, README, evidence, key source files) to chat with an AI agent elsewhere.