- JavaScript 87%
- CSS 8.6%
- HTML 3.7%
- Shell 0.7%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| .forgejo/ISSUE_TEMPLATE | ||
| deploy | ||
| docs | ||
| games | ||
| server | ||
| shared | ||
| site | ||
| test | ||
| .gitignore | ||
| package.json | ||
| play.html | ||
| README.md | ||
| robots.txt | ||
NetDagger Arcade
Retro-inspired single-player HTML5 arcade games (plain JS, HTML5 canvas, CSS) with ad-supported continues. No dependencies: no npm install, no build step. The browser loads ES modules straight from disk, and the server uses only Node built-ins.
| Game | Path | Levels | Issue |
|---|---|---|---|
| Hex Breaker (Breakout/Arkanoid-style, hex bricks) | /games/hex-breaker/ |
1–100 | #20 |
| Block Drop (falling blocks, SRS rotation, 7-bag) | /games/block-drop/ |
1–100 | #27 |
Run it
node server/index.js # or: npm start
# -> http://127.0.0.1:8080/
Needs Node 18 or newer (staging runs 24). Environment variables:
| Var | Default | Meaning |
|---|---|---|
PORT |
8080 |
listen port (staging: 3108) |
HOST |
127.0.0.1 |
bind address; 0.0.0.0 to expose on the LAN |
TRUST_PROXY |
unset | 1 = take the client IP from X-Forwarded-For (behind Apache) |
REWARD_MIN_WATCH_MS |
5000 |
minimum simulated-ad watch time before a reward can be claimed |
REWARD_COOLDOWN_MS |
0 |
per-client gap between rewards |
REWARD_TTL_MS |
600000 |
reward token lifetime |
URLs
/is the home page (site/index.html, designWench's portal), with ad slotshome-topandhome-bottom./games/<slug>/redirects with a 302 to/play.html?game=<slug>(other query params are kept).play.html?game=<slug>&level=Nstarts a given level, which must already be unlocked. Add&dev=1to unlock every level locally./api/health,POST /api/reward/start, andPOST /api/reward/claimmake up the rewarded-ad token stub (same-origin JSON, rate-limited).
The server only serves play.html, robots.txt, ads.txt (when present), shared/, games/ and the contents of site/. The repository files (server/, test/, docs/, *.md, dotfiles) are never served.
Tests
node --test # or: npm test
The tests cover the following:
- Level validity and determinism for all 200 levels. Every Hex Breaker level is clearable: no breakable brick is sealed in by steel.
- Hex collisions, SRS rotation and kicks, line clears, garbage, and the 7-bag.
- Storage, the fixed-timestep loop, and scaling.
- The reward store and the rate limiter.
- The HTTP server: the static allowlist, redirects, and the reward flow.
- Headless bot runs of both games.
Layout
server/ zero-dependency HTTP server + reward-token stub
shared/ game shell: loop, scaling, input (keys/touch/mouse/gamepad), storage, audio, sprites, ads
play.html the game page (canvas, ad placeholders, level select, continue modal)
site/ home page, CSS, fonts, thumbnails (from the art kit)
games/index.json game registry
games/<slug>/ manifest.json, game.js (+ pure logic modules), assets/*.png
deploy/ run.sh / stop.sh / htaccess for staging
test/ node:test suites
Game interface
game.js default-exports a class with init(ctx, api), update(dt) (fixed 1/60 s), render(alpha), onReward(type) and destroy().
api provides:
level,carry,input,keys,sprites,audio,settings()rng(salt)(seeded per game, level and salt)highScore(),setScore(),levelComplete({score, carry}),gameOver({score})
Levels
- Hex Breaker (
games/hex-breaker/levels.js):- Levels 1–10 are hand-made. Levels 11–100 come from a seeded generator with 8 layout patterns, moving rows, and hard (2–5 HP), steel and power-up bricks.
- A flood-fill check and repair step guarantees every breakable brick can be reached.
- Ball speed rises and paddle width shrinks with level.
- Power-ups: wide, sticky, multi-ball, laser, slow, extra life.
- Block Drop (
games/block-drop/levels.js):- Gravity runs from 1 s/row down to 0.018 s/row. Line goals and garbage rows grow with level.
- Preset patterns appear on levels ending in 3 and 7. Rising garbage starts at level 35.
- Every 10th level is a special: dig, quads, survive, and finally 40 lines at level 100.
- Lock delay is 500 ms, falling to 300 ms.
Art
Sprites load from games/<slug>/assets/<name>.png, using the names listed in manifest.json → sprites. They are drawn with image smoothing off.
If a sprite is missing, the game falls back to canvas shapes, so the games still work with an empty assets/ folder.
The art comes from designWench's kit (/workspace/arcade-art). Do not run its _build/build.py, because it wipes the kit folder.
Block Drop has a colour-assist mode that uses the lettered mino-*-cb sprites. Toggle it with the Assist button or the K key; the setting is saved.
Deploy (staging: https://ag1.ndev1.com on rori)
This follows the Hexosphere pattern used on bg1:
git clone ssh://git@git.nd-server0.com:2222/NetDagger/arcade.git ~/apps/arcade # first time; later: git pull
~/apps/arcade/deploy/run.sh # starts node on 127.0.0.1:3108 if not already running
~/apps/arcade/deploy/stop.sh # stop (cron restarts it within a minute)
cp ~/apps/arcade/deploy/htaccess ~/ag1.ndev1.com/.htaccess
The crontab has two entries, alongside the hexosphere ones:
* * * * * $HOME/apps/arcade/deploy/run.sh >/dev/null 2>&1
@reboot $HOME/apps/arcade/deploy/run.sh >/dev/null 2>&1
Logs and the PID file live in ~/apps/arcade/run/. An optional ~/apps/arcade/.env (in KEY=value format) overrides the defaults: PORT=3108, HOST=127.0.0.1, TRUST_PROXY=1.
After a git pull, run deploy/stop.sh && deploy/run.sh.