Underground 2 Revived
Play Need for Speed: Underground 2 (2004) in Chrome and Firefox with WebGPU graphics, Web Audio, up to 120 fps widescreen, controller support, free roam and Online races with friends. Fan project, not
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Draft prepared on 2026-10-05 from a read-only review of the public repo (main, last commit 2026-09-13), the live site, the project's troubleshooting notes (dosvault-jsdos-troubleshooting.md) and previous working sessions. Nothing in the repo was changed while writing it. Items marked (to confirm) could not be verified from the public sources.README 전문 보기 ↗Draft prepared on 2026-10-05 from a read-only review of the public repo (
main, last commit 2026-09-13), the live site, the project's troubleshooting notes (dosvault-jsdos-troubleshooting.md) and previous working sessions. Nothing in the repo was changed while writing it. Items marked (to confirm) could not be verified from the public sources.
DOSVault is a free, browser-based catalog of classic DOS and abandonware games. Visitors pick a game and play it directly in the browser, with no installation, through one of two WebAssembly emulation engines: js-dos (a full DOSBox PC emulated in the browser) or ScummVM (native re-implementation of classic adventure game engines).
The interface imitates a Norton Commander-style DOS file manager: two blue panels (genres on the left, games on the right), a command line, and an F-key bar at the bottom. Games open in draggable, DOS-styled windows inside the page.
| Item | Location |
|---|---|
| Live site | https://dosvault.netlify.app/ |
| Repository | https://github.com/PolZirilli/dosvault (public) |
| Local working copy | /Users/pacata/Documents/Proyectos/dosvault |
| Game bundles | Cloudflare R2, public URL https://pub-13140bd15eda49b4a3f35bc937ab1c58.r2.dev/projects/dosvault/ |
| Owner | Pol Zirilli |
In scope
.jsdos bundles).Out of scope (current decisions)
DOSVault is a static site with no build step: plain HTML, CSS and vanilla JavaScript, served by Netlify straight from the repository. All dynamic behavior happens in the visitor's browser.
Visitor's browser
├─ index.html + css/ + js/ ← served by Netlify (from GitHub repo)
├─ data/games.json, data/genres/* ← catalog, same origin, lazy-loaded per genre
├─ Game bundles (.jsdos / ScummVM) ← Cloudflare R2 (fetched on launch; HEAD for size/date)
├─ js-dos v7 (vendored) ← emulates the DOS PC
├─ ScummVM WASM (vendored, iframe) ← adventure game engines
└─ Third-party lookups (client-side, no keys):
• GitHub API → date of last commit to data/games.json
• Netlify Forms → Help/Contact form submissions
dosvault/
├─ index.html Single page: panels, F-key bar, all modals, script loading
├─ favicon.png
├─ css/
│ ├─ style.css Full site styling (DOS/Norton Commander look)
│ └─ fonts/ PxPlus IBM VGA8 (self-hosted, CC BY-SA 4.0) + license
├─ js/
│ ├─ app.js Main application: catalog, navigation, windows, modals,
│ │ key remapping, gamepad, test-bundle tool (~1,700 lines)
│ ├─ i18n.js ES/EN dictionaries, genre labels, language detection
│ ├─ scummvm-engine.js Wrapper that runs ScummVM inside an iframe
│ └─ vendor/
│ ├─ js-dos/ js-dos 7.1.0 (js-dos.js, wdosbox.js/.wasm, css)
│ └─ scummvm/ ScummVM WASM build + launcher.html + fflate + engine plugins
├─ data/
│ ├─ games.json Genre index (name, count, URL of each genre file)
│ └─ genres/*.json One file per genre with its game entries
└─ .github/workflows/
└─ build-scummvm.yml Manual workflow that compiles ScummVM to WASM
data/games.json — genre index{
"genres": {
"race": { "name": "Carreras", "count": 17, "url": "data/genres/race.json" }
}
}
name: fallback label (the visible label normally comes from I18N_GENRES in js/i18n.js).count: maintained by hand. It is shown in the Files column only until the genre files finish loading; from then on the column shows the number of visible games of the genre (games whose bundle returned 404/410 on R2 are not counted). Genres with 0 games are hidden.url: genre file, loaded only when the visitor opens that genre (lazy loading with in-memory cache).Current genre ids: fps, rts, platformer, avg, rpg, sim, arcade, action, race, sports.
data/genres/<id>.json — game entries{
"id": "race",
"name": "Carreras",
"games": [
{
"id": "deathrally",
"name": "DEATHRALLY",
"genre": "race",
"added": "2026-08-11",
"year": "1996",
"cover": "https://thumbnails.libretro.com/DOS/Named_Boxarts/Death%20Rally.png",
"bundle": "https://pub-…r2.dev/projects/dosvault/deathrally.jsdos"
}
]
}
| Field | Required | Purpose |
|---|---|---|
id | yes | Unique key; also used for window ids and cache keys |
name | yes | Short DOS-style name shown in the list and window title |
title | no | Full display title; preferred over name for sorting and tooltip |
genre | yes | Must match the genre id |
added | yes | YYYY-MM-DD; drives the "New games" popup |
year | yes | Release year, shown in the new-games popup |
cover | yes | Box-art image URL (libretro thumbnails). Not displayed anywhere at the moment (it was only used by the removed Info popup) |
bundle | yes | Absolute URL of the bundle on R2 |
engine | no | "scummvm" to use ScummVM; omitted = js-dos |
lang | no | "es"/"en", shown in the Language column; defaults to EN |
Size and date shown in the right panel are not stored in JSON: they are read live from the bundle with an HTTP HEAD request (Content-Length / Last-Modified), which requires the R2 bucket's CORS policy to allow the site's origin.
The same HEAD decides whether a game is listed. Rule: a game whose bundle is not on R2 must never be visible, not even for an instant. On load, every bundle in the catalog is checked in the background (at most 6 requests at a time, 15 s timeout each; the games of the open genre jump the queue and skip the 6-request limit). A game with a bundle is shown only once its HEAD has finished:
Games without a bundle field are always visible, as before. While the open genre still has unchecked games, the right panel shows "Checking games…" ("Verificando juegos…") instead of a partial list, and Enter/Run do nothing until it fills. The Files count of a genre uses the count from games.json until all its games are checked, then the number of visible games; a genre with 0 visible games is hidden. data/ is never modified: the filter is applied at runtime.
Catalog snapshot at the time of this review: 99 games, 85 on js-dos and 14 on ScummVM.
js/vendor/js-dos/, with emulators.pathPrefix pointing there.Dos(container, {}).run(bundleUrl). No custom extraction logic of our own..jsdos = a regular zip containing the game files plus .jsdos/dosbox.conf (with the [autoexec] that mounts C: and starts the game).[⛶] button requests real browser fullscreen. Trade-off: in real fullscreen, Esc exits fullscreen instead of reaching the game (browser standard, cannot be overridden)..github/workflows/build-scummvm.yml (manual workflow_dispatch, compiles scummvm/scummvm with Emscripten, publishes scummvm-wasm.zip as a GitHub Release; artifacts are then copied by hand into js/vendor/scummvm/).scumm, scumm_7_8, sci, sci32, agi, agos, agos2, sky, queen, drascula, lure, gob, tucker, touche, cine, cruise, kyra, parallaction.js/vendor/scummvm/launcher.html?bundle=<url>) so that relative asset paths resolve correctly and each game gets an isolated JS context.saves, extras, docs, dosbox, etc.), flattens it into /game, pre-loads all engine plugins (data/plugins/*.so), and starts ScummVM with --path=/game auto-detection.<id>.scummvm (the extension is organizational only; fflate ignores it). Existing catalog entries still use .zip (see section 10).[≡] titlebar button simulates Ctrl+F5 to open ScummVM's Global Main Menu (save/load/options). A one-time "how to play with ScummVM" hint appears before the first ScummVM launch, with a "don't show again" option.| Feature | How it works |
|---|---|
| Two-panel navigation | Genres on the left, games on the right; ↑/↓ move, ← goes to the left panel, → to the right panel, Tab switches, Enter opens/runs. The selected row is kept scrolled into view, and switching ES/EN keeps the selected game. While any popup is open (Controls, Help, New games, F9 Test bundle, ScummVM hint) navigation is blocked and Esc closes it (on the ScummVM hint, Esc works like its close button and the game starts). Keyboard goes entirely to the game while a game window has focus; clicking outside returns it to the shell. |
| F-key bar | F1 Controls · F3 Run · F4 Refresh · F5 Help · F9 Test bundle · F10 Close. |
| Game windows | Draggable, maximizable, multiple at once; z-ordering and focus handling in app.js. |
| Key remapping | "Controls" popup: Navigation tab (wired), In-game tab (action1/action2 reserved, not wired yet), Gamepad tab. Uses KeyboardEvent.code. |
| Gamepad support | Browser Gamepad API (tested with Xbox Series X, "standard" mapping). Buttons are mapped to keyboard keys and sent to the game as synthetic key events. Remappable. |
| New games popup | Shown once per load, after all R2 checks finish. Lists only games added (available now, not available on this browser's previous visit). A game is listed only when R2 confirmed its bundle (or it has no bundle field); games that could not be checked (network/CORS) are reported once R2 confirms them, and a game whose bundle is 404/410 is never listed. Removed games are not shown: a game whose bundle is not on R2 must not appear anywhere on the site. First visit: no popup. Visitors with only the old dosvaultLastVisit key get the old added-date criterion once, with the same R2 filter. |
| Help / Contact | Netlify Forms (name="contacto", honeypot field): feedback, game requests, bug reports. |
| Test a local bundle (F9) | Loads a local .jsdos or ScummVM zip through a blob: URL; the file never leaves the browser. Used to test a bundle before uploading it to R2. |
| i18n | Spanish for any es-* browser language, English for everything else; manual ES/EN switch saved per browser. |
| Mobile block | Full-screen notice on phones/tablets. |
| Key | Content |
|---|---|
dosvaultControls | Keyboard remapping |
dosvaultGamepadControls | Gamepad remapping |
dosvaultLang | Chosen UI language |
dosvaultLastVisit | Date of last visit (for "New games") |
dosvaultAvailableGames | Ids of the games available on the last visit: { v: 2, ids: [<id>, ...] } (for "New games"). The older { v: 1, games: { <id>: {...} } } format is still read (only its keys are used) |
dosvaultScummvmHintDismissed | ScummVM hint dismissed |
dosvault-bundle-creator (build_jsdos.py / build_scummvm.py), ordosvault-builder (js/core.js + js/app.js, kept in a separate repo/zip, with feature parity with the skill).projects/dosvault/.data/genres/<genre>.json and update count in data/games.json.main; Netlify redeploys automatically (to confirm).| Rule | Reason |
|---|---|
| Max 300 MB per bundle; builders abort with exit code 6 | Cloudflare hosting limit |
cycles=20000 (fixed), never cycles=auto | auto hangs heavier games (especially DOS4GW) in the browser |
keyboardlayout=us | Consistent key mapping |
| Explicit zip directory entries for every folder level | js-dos v7 freezes on "Extracting" with 2+ nested levels lacking them |
.jsdos for js-dos, .scummvm for ScummVM | Naming convention for the bucket |
| Test on a throwaway copy | Games write config files on first run that would otherwise end up in the bundle |
Drop installers, native Windows .exes and pack extras | Smaller bundles; avoids extraction freezes |
Large bundles (roughly 40–90 MB and above) can freeze during extraction in js-dos v7 even under 300 MB. This is a known upstream issue with no fix on our side; the only mitigation is reducing content (with the owner's approval).
| Item | Purpose |
|---|---|
dosvault-bundle-creator (Claude skill) | Builds .jsdos and .scummvm bundles from game archives |
dosvault-builder (web tool) | Same build engine in the browser (JSZip) |
dosvault-jsdos-troubleshooting.md | Case log of every bundle problem diagnosed and how it was fixed |
build-scummvm.yml | Rebuilds the ScummVM WASM engine when needed |
Skill updates only take effect once the .skill file delivered in a session is saved by the owner; if a skill still shows old behavior (e.g. cycles=auto), it was not saved.
These were noticed while reading the code. None has been modified.
count in games.json totals 69, but the genre files contain 99 games (e.g. sports says 4, has 13; race says 17, has 24). The Files column therefore shows wrong numbers.CONTROL_ACTIONS are F1=Help, F2=Controls, F4=Run, F5=Refresh (F3 unbound). Pressing F1 on the keyboard likely opens a different popup than the bar label says (to confirm in the browser)..zip for its 14 ScummVM bundles and the F9 picker filters to .zip, while the skill and builder now output .scummvm. New .scummvm files will be hidden by default in the F9 file picker.action, but I18N_GENRES uses the key accion, and sports has no entry at all. Both fall back to the Spanish name from games.json, so they won't be translated in English mode.lang field in any entry, so every game shows EN in the Language column, including Spanish releases.dosvault-files-lang-columns.patch (root), and 1-byte placeholder files css/fonts/txt and js/vendor/scummvm/this.r2.dev address. Cloudflare positions these as development endpoints with rate limiting; a custom domain is the usual production setup (worth evaluating).main? Any environment variables, redirects or headers set in the Netlify UI?dosvault-builder repo lives and whether it should be documented here.