Play (jocor_cartridge), WebGames, Minecraft — the Nextcloud game apps + harness
  • JavaScript 64.5%
  • PHP 17.2%
  • CSS 12.1%
  • Python 3.2%
  • C 1.7%
  • Other 1.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-14 21:02:40 +02:00
docs/play-2026-09 Play 3.3.4: sync the live-identical working copy, harness, tools and plans 2026-09-14 02:01:38 +02:00
emulatorjs-patch Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00
harness Play 3.3.5: WebGames door shows whole screenshots at every width 2026-09-14 02:18:08 +02:00
jocor_cartridge Play 3.4.0: Persona Nova door (play.jo-cor.com/nova/) and a Play dashboard widget 2026-09-14 21:02:40 +02:00
jocor_eaglercraft Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00
jocor_flashback Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00
linkcore Add the link-cable core sources (mGBA lockstep, two GBAs in one page) 2026-09-14 02:04:59 +02:00
netplay-server Play 3.3.4: sync the live-identical working copy, harness, tools and plans 2026-09-14 02:01:38 +02:00
tools Run every Play unit suite from the repo: package.json + tools/test.sh 2026-09-14 02:06:29 +02:00
.gitignore Run every Play unit suite from the repo: package.json + tools/test.sh 2026-09-14 02:06:29 +02:00
arcade-netplay-proxy.conf Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00
check-access.php Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00
fetch-boxart.py Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00
fetch-swf.sh Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00
lib-arcade.js Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00
package-lock.json Run every Play unit suite from the repo: package.json + tools/test.sh 2026-09-14 02:06:29 +02:00
package.json Run every Play unit suite from the repo: package.json + tools/test.sh 2026-09-14 02:06:29 +02:00
push-file.sh Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00
README.md Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00
retry-swf.sh Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00
rom-list.txt Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00
shots.js Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00
test-apps.js Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00
test-crosscheck.js Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00
test-invite.js Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00
test-netplay.js Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00
test-newuser.js Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00
test-singleplayer.js Snapshot of the 2026-09-06 sources before syncing Play 3.3.4 2026-09-14 02:01:02 +02:00

Three game apps for Nextcloud (CT 100)

Built 2026-09-06. These are the sources; the deployed copies under custom_apps/ on CT 100 are the live ones.

App Nav name What it is
jocor_cartridge Cartridge 69 console ROMs from a Team folder, EmulatorJS, box art, netplay with invites
jocor_flashback Flashback 1,314 mirrored Flash games played by self-hosted Ruffle
jocor_eaglercraft Eaglercraft Minecraft 1.12.2 in the browser, framed from eaglercraft.ir

jocor_arcade was the first version of Cartridge and is gone — disabled, removed, backed up at CT100:/root/nc-app-backups/jocor_arcade-superseded-by-cartridge-20260906.tgz.

Not in this tree

  • The 3.1 GB of .swf files. They live only at CT100:/var/lib/docker/volumes/nextcloud-server_nextcloud/_data/custom_apps/jocor_flashback/games/. Re-mirror with fetch-swf.sh then retry-swf.sh (the second one handles the ~40 games whose file is not named after its slug). A redeploy of Flashback must never rm -rf the app directory — copy the subdirectories individually and leave games/ alone.
  • The ROMs. Team folder id 2 (Games), group arcade, read-only.

Running the tests

They drive real Chromium against the live instance over the Funnel URL and log in as real accounts.

cd /root/jocor-games
npm install playwright-core@1.55.0          # if node_modules is absent

P='…'                     node test-singleplayer.js   # Cartridge, one player
P1='…' P2='…' ID=7042     node test-netplay.js        # two players, one room
P='…'                     node test-crosscheck.js     # a third account
P='…'                     node test-apps.js           # all three apps
P1='…' P2='…' ID=7025     node test-invite.js         # invite → notification → join

ID is a Nextcloud file id from /apps/jocor_cartridge/api/games; it is not stable across a re-upload of the ROMs. 7025 is Super Mario World.

Accounts: arcade1 (Player One), arcade2 (Player Two), arcadeqa (Arcade QA), all in group arcade.

Things that cost real time — full detail in the jocor-arcade-app memory note

  • Netplay needs an https entrance. On plain http the browser has no WebRTC at all and a room connects to nothing, silently.
  • Never check an emulator canvas with drawImage — WebGL without preserveDrawingBuffer reads back solid black, which looks exactly like a dead emulator. Screenshot the element instead.
  • Nextcloud's root .htaccess only passes a fixed extension allowlist through to static files. .data (EmulatorJS cores) and .swf are not on it. Both apps carry their own .htaccess to deal with that — Cartridge to allow its cores, Flashback to deny its games (they are served by an authenticated route instead, so the mirror is not public).
  • NC 34 cannot emit 'unsafe-eval' at all, which is why the EmulatorJS cores are pre-extracted at build time rather than unpacked in the browser.

Who can play what (2026-09-06)

App Needs Why
Flashback a Nextcloud login, nothing else games are app assets, streamed by an authenticated route
Eaglercraft a Nextcloud login, nothing else it is a frame
Cartridge membership of a group with read on Team folder id 2 the ROMs are files, so Nextcloud's own permissions decide

All three apps are enabled instance-wide (enabled: yes, not a group list), so they appear in everyone's app menu. Only Cartridge can be empty for someone, and when it is, it says so and points at the fix rather than looking broken.

Team folder Games (id 2) grants read to arcade, admin and jo-cor-users — between them every path an account currently arrives by, including self-registration (the registration app puts new sign-ups in admin). Every human account is also in arcade directly.

A brand-new account created with no groups at all still sees no ROMs. One line fixes it, and it is worth doing at creation time:

occ group:adduser arcade <uid>

check-access.php answers this for the whole instance at once — it asks LibraryService the same question the app asks, per account:

docker cp check-access.php nextcloud-server:/tmp/ && \
  docker exec -u www-data nextcloud-server php /tmp/check-access.php

Two accounts legitimately show no games: chamade-bot-wq912lqz and, until it is re-enabled, the disabled account craig.

Who can be invited

InviteController::players() lists everyone who can open the game in front of you, not everyone who shares a group with you. That predicate is deliberate: the group version broke as soon as the household grew past one group, and it could list people who had no access to the library. The invite itself is authorised the same way, so the picker can never offer someone the invite would then refuse.

Two consequences to expect: a service account with library access (nyx-agent, via admin) does appear in the list, and an account that has never logged in does not, because it has no home storage to resolve the ROM against yet.