Every game on this site is a configuration object passed to the shared engine in
assets/js/engine.js. You do not write game code to add a game - you describe one.
_src/games_data.py{
"slug": "my-new-game",
"title": "My New Game",
"h1": "My New Game - Play Free Online",
"meta_title": "My New Game - Play Free Online | Brick Breaker Games",
"meta_desc": "150 characters describing what makes this game different.",
"short": "One line for the game card.",
"description": "Two lines for JSON-LD and the data file.",
"category": "Classic", # display label
"categories": ["classic", "skill"], # filter chips, lowercase
"difficulty": "Medium", # Easy | Medium | Hard | Expert
"controls": "Keyboard, mouse and touch",
"control_keys": ["keyboard", "mouse", "touch"],
"hook": "Short badge line",
"objective": "What the player is trying to do.",
"what_makes_it_different": "A paragraph. Be specific - this is the anti-clone section.",
"tips": [ ... 5 tips ... ],
"faq": [ (question, answer), ... 4 items ... ],
"related_games": ["slug", "slug", "slug"],
"related_articles": ["slug", "slug", "slug"],
"primary_category": "brick-breaker-games", # one of the six category slugs
"engine": { ... see below ... }
}
| Key | Type | Meaning |
|---|---|---|
mode | string | Label only: levels, endless, timed, puzzle, survival |
lives | int | Lives. Use 0 with shots for puzzle modes |
shots | int | Total ball budget for the run; replaces lives |
aim | bool | Show a sweeping aim line and launch along it |
ballSpeed | number | Starting speed in logical units per second (260-380 is the useful range) |
speedPerLevel | number | Added to base speed each level |
accelPerHit | number | Speed added on every paddle return |
maxBallSpeed / minBallSpeed | number | Hard limits |
paddleWidth / paddleSpeed | number | 92-116 and 520-660 are the tuned ranges |
ballRadius | number | 6-8 |
powerUps | array | Any of widen, shrink, multi, slow, fast, fire, life, score2, magnet, shield |
powerUpChance | 0-1 | Drop probability per destroyed brick |
powerUpDuration | seconds | Timed effects, default 10 |
timeLimit / timeRefill / timeBonus | number/bool/number | Countdown seconds, refill each level, points per leftover second |
descendEvery | seconds | Push the whole field down one row on this interval |
endless | bool | Cycle the level list forever instead of ending |
comboScoring | bool | Multiplier up to 10x, reset on paddle contact |
levelBonus / livesBonus | number | End-of-level points |
seed | int | Fixes randomised layouts so puzzles are repeatable |
theme | object | bricks[], bg, wall, paddle, ball, plus optional glow, round, flat, grid, unbreakable, explosive, bonus, mystery, boss, aim |
levels | array | See below |
{
"name": "The Tunnel",
"pattern": "tunnel", # rows pyramid diamond checker fortress tunnel
# zigzag waves columns scatter arch
"rows": 6, "cols": 11,
"mix": "nnnnsp", # weighted string: one character per weight unit
"brickHeight": 22, # optional
"top": 26, # optional offset below the top wall
"moving": true, # optional: slide selected rows horizontally
"movingEvery": 2, "movingAmp": 30, "movingSpeed": 0.7
}
Brick type characters:
| Char | Brick | Hits | Points |
|---|---|---|---|
n | Normal | 1 | 10 |
s | Strong | 2 | 25 |
t | Reinforced | 3 | 45 |
u | Unbreakable | - | 0 |
b | Bonus | 1 | 60 |
p | Power (always drops) | 1 | 15 |
x | Explosive | 1 | 30 |
m | Mystery | 2 | 35 |
B | Boss | 12 | 400 |
. | Empty | - | - |
mix can also be an object: {"rows": ["s","n","u"], "edge": "u", "core": "x",
"fallback": "n"}. edge and core only apply to the
fortress pattern.
Levers that produce real differences: failure system (lives / ball budget / timer / descent), scoring rule (flat / combo / time bonus), power-up pool including harmful capsules, brick mix (unbreakable and explosive change level shape most), acceleration, and aim-based launching.
py _src/build.py
This creates games/<slug>/index.html, generates the featured image, adds the
game to data/games.json and the search index, adds it to the directory, the XML
sitemap and the HTML sitemap.
Several of those checks are automated. py _src/build.py --smoke writes
_smoke.html to the project root with every game's real configuration injected. Opening
it drives each game headlessly for five minutes of simulated time with a tracking paddle, then
reports per game whether the engine constructed, whether bricks were destroyed, how many levels
cleared, whether the ball ever left the playfield, and whether any JavaScript error was thrown.
# terminal 1 py _m http.server 8000 # terminal 2 - any Chromium browser works chrome --headless=new --virtual-time-budget=40000 --dump-dom http://localhost:8000/_smoke.html
Or simply open http://localhost:8000/_smoke.html in a normal browser and read the
output. A healthy line looks like:
arcade-breakout: PASS frames=18000 state=running score=1780 levelClears=0
bricksStart=65 bricksLeft=2 escaped=0
FAIL(no score) with bricks remaining - that means the ball
physically cannot reach part of the level. This is exactly how the sealed-core bug in the original
fortress pattern was found: an unbreakable perimeter with no gate made every brick
inside it unreachable, and the level could never be completed. The pattern generator now always
leaves a two-column gate in the bottom wall._smoke.html is disallowed in robots.txt and does not need to be
uploaded. It is regenerated whenever you pass --smoke, so it always tests the current
configurations rather than a stale copy.