Add scummvm to the Dockerfile. Its binary lives at /usr/games/scummvm (Debian's convention for game packages), not reliably on $PATH under a non-login shell, so manifests reference it by absolute path. Generalize the manifest schema from a bare "zip" filename (implicitly under Games\dosbox\ on the SMB share) to "zip_path" (a full path relative to the share root), since the SCUMM games' zips live in their own folders (Games\Monkey Island\, Games\Indiana Jones\, etc.) rather than being colocated with their manifest like stuntcar/t7g were. Manifests themselves still all live in the Games\dosbox\ catalog directory regardless of where the actual zip sits. Added and verified (install/start/stop/uninstall via monkey2) manifests for: monkey, monkey2, atlantis, indy3, tentacle. Skipped the German CD release of Day of the Tentacle (loose files at the zip root, no single top-level folder - incompatible with the current extraction convention) and Curse of Monkey Island (untested, much larger). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NiNnj78HGx1KWyCCo39HSz
5.5 KiB
TODO
-
~
Reduce image size ofDone in two steps:jayfield/dosbox-novnc(currently2.3GB).- Merged the game download/extract steps and the unzip/smbclient install into a single layer (so the downloaded zips and the packages only needed to extract them no longer persist in the final image). 2.31GB -> 1.6GB.
- Stopped baking the games into the image at all (927MB of that was just t7g's two CD
ISOs).
run.shmounts a named volume (dosbox-games) so installed games persist across--rmrestarts. 1.6GB -> ~690MB. Container now needs network access tovlda-01at runtime (not just build time) to install games. - Dropped the auto-download at container startup entirely.
scripts/setup_server.pyis a small stdlib-only HTTP server (started alongside Xvnc/fluxbox/websockify) that serves an HTML page on${SETUP_PORT}(70${DISPLAY_NUM}, published as7099byrun.sh) listing every*.zipon the SMB share with an Installed/Install status per game; the user clicks "Install" to fetch+extract a specific game into${GAMES_HOME}on demand.
-
Manifest-driven games + Start/Stop/Uninstall: games are no longer discovered from raw
*.zipfiles on the share.setup_server.pylists*.jsonmanifests instead (one per game, in theGames\dosbox\catalog directory), each declaringname/title/zip_path/start_cmd. The web page grew Start/Stop/Uninstall buttons alongside Install, driven entirely by that manifest — nothing about a game's identity or how to run it is hardcoded in the image anymore. Started as astuntcar-only pilot, now extended to 6 games (see the SCUMM item below).t7gstill has no manifest and won't show up in the setup page until one is added (t7g.jsonwith astart_cmdfor itsdosbox-0.74-3.conf).game.sh/scripts/start_game.sh(the olddocker exec-based launch path, with its hardcodedDOSBOX_VERSION/run.batconvention) were intentionally left untouched during the pilot and still overlap with the new Start button — worth reconciling (or removing) once every remaining game has a manifest. -
Create manifests for SCUMM engine gamesDone:scummvmadded to the Dockerfile (/usr/games/scummvm, not on$PATHby default under a non-login shell — manifests use the absolute path). Manifests live in the usualGames\dosbox\*.jsoncatalog directory on the share, but theirzip_pathnow points at wherever the game's zip actually already lived (Games\Monkey Island\...,Games\Indiana Jones\..., etc.) — this required generalizing the manifest schema from a barezipfilename (implicitly underGames\dosbox\) to a fullzip_pathrelative to the share root, since these games weren't colocated with dosbox's. Added and verified end-to-end (install/start/stop/uninstall) viamonkey2:monkey— The Secret of Monkey Islandmonkey2— Monkey Island 2: LeChuck's Revengeatlantis— Indiana Jones and the Fate of Atlantisindy3— Indiana Jones and the Last Crusadetentacle— Day of the Tentacle
Skipped the German CD release of Day of the Tentacle on the share (
Day Of The Tentacle (CD DOS, German).zip) — unlike every other zip here, it doesn't wrap its contents in a single top-level folder (loose files at the zip root plus a strayMANIAC/dir for the embedded Maniac Mansion easter egg), so it doesn't fit the current "zip's top-level folder == install name" extraction convention. Also skipped Curse of Monkey Island (much larger, untested) — could be added the same way if wanted.ScummVM's own game-target IDs (
monkey,monkey2,atlantis,indy3,tentacle) happened to exactly match each zip's existing top-level folder name, so no change was needed to the install/extraction logic itself, only to where zips are looked up from. -
Get game sound actually audible during play.
--device /dev/sndis passed through andalsa-utilsis installed, so DOSBox can write to an ALSA device inside the container, but VNC/noVNC only ever streams video, not audio — nothing currently carries that sound out to the browser.Target latency is a few tens of ms, not seconds — that rules out the "obvious" approach of a PulseAudio null sink piped through
ffmpeginto a compressed (mp3/ogg) HTTP/Icecast-style stream consumed by an<audio>tag: codec frame buffering plus the<audio>element's own jitter buffer realistically puts that in the 1-3s range, no matter how it's tuned.Concrete approach instead: PulseAudio null sink → capture raw/lightly-buffered PCM (small frames, e.g.
parecwith a short--latency) → push those frames to the browser over a plain WebSocket (new endpoint alongsidesetup_server.py, or a small dedicated process) → browser side, feed them straight into the Web Audio API via anAudioWorkletNode(not<audio>, notScriptProcessorNode— that's deprecated and has worse latency) for near-real-time scheduled playback. No container/codec framing in the path at all.Build this to be reusable across the other noVNC-family projects (
docker-xserver-novnc,docker-sdr-novnc), not dosbox-specific — it's a "browser audio + noVNC" concern, nothing about it is really about DOSBox. Follow thedocker-common/scripts/signals.shprecedent (see thedocker-commonrepo): keep the generic PulseAudio-sink/WebSocket/AudioWorklet piece project-agnostic there, then copy it (not symlink) into each project's ownscripts/the same way signal handling is shared, so a fix in one place gets propagated by hand to the others.