Skip to content

[app] Commit Breaker — Arkanoid where the wall is your contribution graph #7

@Circuit-Overtime

Description

@Circuit-Overtime

Updated 2026-05-20 with full mechanics, src/ layout, and challenge knobs.

TL;DR

A brick-breaker whose wall is a GitHub contribution graph. The ball + paddle live below; bricks are the commit cells, coloured by activity level and harder to break the brighter green they are. Clearing the wall = clearing a year of commits.

Ships in apps_market/ (opt-in via the on-device App Market) so it doesn't burn a default-drawer slot.


🎮 Core loop

  1. App fetches the player's contribution graph (reuses apps/commits/'s cached fetch + offline fallback).
  2. Graph renders as a brick wall at the top of the screen — 7 rows × ~32 most-recent weeks.
  3. Paddle at the bottom (D-pad LEFT/RIGHT). A launches ball.
  4. Ball bounces off paddle / walls / bricks. Bricks lose HP per hit, shift shade, vanish.
  5. Drop the ball below the paddle → lose a life. 3 lives total.
  6. Clear the whole wall → "year cleared" screen with time + score.

🧱 Brick model

GitHub shade HP Base points Visual
Level 0 (no contribs) empty cell
Level 1 (light green) 1 10 #9be9a8
Level 2 (mid green) 2 25 #40c463
Level 3 (deep green) 3 50 #30a14e
Level 4 (darkest) 4 100 #216e39

Each hit drops HP by 1 and shifts the brick one shade lighter, so the player sees damage build up visually before the brick pops.


🔥 Difficulty / challenge knobs

The trick with breakout is that "just bricks" gets boring fast. These are the layers that make it sticky:

  1. Paddle-position deflection. Ball bounce angle is set by where on the paddle it hits, classic Arkanoid feel. Centre = straight up, edges = ±60°. No 1980s "ball always returns at the same angle" boredom.
  2. Speed ramp. Ball base speed increases by 5% every 25 bricks broken. Caps at 2× start.
  3. Combo multiplier. Bricks broken between paddle touches stack a multiplier (×2 after 5, ×3 after 12, ×4 after 25). Drops back to ×1 the moment the paddle touches the ball.
  4. Power-up drops. Every Nth brick (~1/30) drops a falling power-up the paddle can catch:
    • WIDE — paddle 1.5× width, 10 s.
    • MULTI — ball splits into 2; lose all to lose a life.
    • SLOW — ball 60% speed, 8 s.
    • STICKY — next paddle-bounce holds the ball; press A to release with aim.
  5. Streak columns. If the source data has 5+ consecutive level-4 cells in a column (a "real" contribution streak), the column reads as a single boss-column: each cell in it has +1 HP but clearing the whole column gives a flat +500 bonus.
  6. Dense weeks = harder. A graph from a busy contributor is genuinely a tougher level than a sparse one. Use someone else's username in secrets.GITHUB_USER for a different challenge.
  7. Year mode vs Endless mode. Year = one year, finite bricks, finish line is "clear the wall." Endless = infinite scrolling weeks from oldest data + procedural fallback when data runs out; ball gets faster every cleared row.

🎨 Layout (320 × 240, landscape)

┌───────────────────────────────────────────────────┐ ← y=0
│ COMMIT BREAKER          12,540  ×3  ❤❤❤          │   header (28 px)
├───────────────────────────────────────────────────┤
│ ░░▓▓██▓▓░░░▓▓██░░░░▓▓██▓▓░░░░██▓▓░░▓▓░░          │   ┐
│ ░░▓▓██▓▓░░░▓▓██░░░░▓▓██▓▓░░░░██▓▓░░▓▓░░          │   │ brick wall
│ ░░▓▓██▓▓░░░▓▓██░░░░▓▓██▓▓░░░░██▓▓░░▓▓░░          │   │ 7 × ~32
│ ░░▓▓██▓▓░░░▓▓██░░░░▓▓██▓▓░░░░██▓▓░░▓▓░░          │   │ ~64 px tall
│ ░░▓▓██▓▓░░░▓▓██░░░░▓▓██▓▓░░░░██▓▓░░▓▓░░          │   │
│ ░░▓▓██▓▓░░░▓▓██░░░░▓▓██▓▓░░░░██▓▓░░▓▓░░          │   │
│ ░░▓▓██▓▓░░░▓▓██░░░░▓▓██▓▓░░░░██▓▓░░▓▓░░          │   ┘
│                                                   │
│              ⚙ MULTI                              │   power-up drop
│                                                   │
│                   ○                               │   ball
│                                                   │
│                                                   │
│              ▬▬▬▬▬▬▬▬                             │   paddle (D-pad)
├───────────────────────────────────────────────────┤
│ A=launch  L/R=move  B=pause  HOME=back           │   hint (16 px)
└───────────────────────────────────────────────────┘ ← y=239

Cell pitch ~9×8 px keeps the graph visually GitHub-like at this scale.


🎮 Controls

Button Action
LEFT / RIGHT Move paddle
A Launch ball / catch with STICKY power-up
B Pause
HOME Exit (intercepted by OS — on_home_press not needed)
(optional) IMU tilt Alternate paddle control; toggle in pause menu

📁 Directory (new src/ layout)

apps_market/commit_breaker/
├── __init__.py
├── manifest.json                 name, version, author, icon
├── main.py                       3-line shim → re-exports App
└── src/
    ├── __init__.py
    ├── app.py                    lifecycle hooks only
    ├── game.py                   pure logic — ball physics, brick HP, collisions
    ├── render.py                 drawing (wall, ball, paddle, HUD, overlays)
    ├── grid.py                   contribution-data → brick grid (reuses commits/ cache)
    └── powerups.py               drop / catch / effect timer logic

See https://oreo.elixpo.com/docs/apps/ for the full app-writing convention and apps/snake/ for the reference layout.


🧩 Data source

Reuse apps/commits/'s fetch:

from apps.commits.src.commits import fetch_contributions, demo_grid

grid = fetch_contributions(secrets.GITHUB_USER) or demo_grid()
# grid is a list of 7 rows × N weeks of ints 0..4

Cache TTL is already 1 h via oreoOS.cache so the brick wall doesn't refetch every launch. Offline / first-boot → falls back to a hand-crafted demo grid.


✅ Acceptance criteria

  • App lives at apps_market/commit_breaker/ with the src/ layout above.
  • Manifest icon is commit_breaker_icon.png (prompt at prompts/icons/commit_breaker_icon.md — generate with Pollinations).
  • App appears in the on-device App Market tile after the next deploy.
  • D-pad moves paddle smoothly at ~30 FPS.
  • Ball physics: paddle-position deflection, wall bounces, brick collisions, lose-life on bottom-edge.
  • Brick wall sourced from real contribution data with offline fallback.
  • HP-by-shade colouring; bricks visually lighten as they take damage.
  • 3-life system; "GAME OVER" panel with retry on A.
  • "YEAR CLEARED" panel on full wall clear with final score + time.
  • At least 2 of the difficulty knobs above implemented (combo multiplier + paddle deflection are the minimum bar for "feels like Arkanoid").
  • Pause via B; pause panel matches OS overlay style.
  • Persistent high score under apps_market/commit_breaker/hiscore.txt.

🎯 Stretch goals

  • IMU-tilt paddle (toggle in pause menu).
  • Power-ups (any subset of WIDE / MULTI / SLOW / STICKY).
  • Endless mode.
  • Streak-column boss bonus.
  • Particle effect on brick pop (reuse pixelfont scale for a quick "+25" flash).
  • Sound — drop a tiny PWM buzzer beep on paddle-bounce / brick-pop if the badge ever gets one.

💬 Open questions

  • Paddle physics curve. Linear angle-by-position is the safe default; a slight non-linear curve (more deflection near the edges) tends to feel better. Tune in playtest.
  • IMU as primary or alternate? D-pad is more reliable; IMU is fun but error-prone at high speed. Default to D-pad, IMU as opt-in.
  • Should "today's cell" be a boss? Could make the bottom-right cell (most recent day) a 5-HP brick worth +200 points, as a small narrative beat.

Metadata

Metadata

Labels

DEVCategory: DevMEDIUMPriority: Medium

Type

No fields configured for Task.

Projects

Status

Todo

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions