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 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Write Nintendo DS games in TypeScript, preview in a browser, and build real .nds ROMs.
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
Write a small Nintendo DS game in TypeScript, preview the same compiled game in a
browser, and build an actual .nds ROM with BlocksDS.
An MIT-licensed v0.1 homebrew engine prototype for small dual-screen games.
Game logic, a browser preview, and a native DS runtime live in one independent
source tree.
Requirements: Node.js 22.12+ and npm. ROM builds additionally require Docker.
The Docker image is pinned by digest. Docker may download it on the first build;
compilation inside the container uses no network.查看完整 README ↗Write a small Nintendo DS game in TypeScript, preview the same compiled game in a
browser, and build an actual .nds ROM with BlocksDS.
An MIT-licensed v0.1 homebrew engine prototype for small dual-screen games. Game logic, a browser preview, and a native DS runtime live in one independent source tree.
Requirements: Node.js 22.12+ and npm. ROM builds additionally require Docker. The Docker image is pinned by digest. Docker may download it on the first build; compilation inside the container uses no network.
git clone https://github.com/jiwonMe/nds-ts.git
cd nds-ts
npm ci
npm run dev # Browser preview, http://localhost:5174
npm run build # Actual DS ROM: build/nds-ts-demo.nds
Change examples/dual-screen/main.ts and rebuild. The game's movement, gravity,
jump, touch behavior, palette changes, and sound decisions are all in that TS file.
No C++ game implementation needs to be edited.
Controls: D-pad / keyboard arrows to move, A / Space / Z to jump, B / X to change the accent, and the bottom touchscreen / pointer to teleport. Browser audio starts after Enable sound is pressed. The ROM plays sound through DS hardware.
Load the ROM with a DS emulator or a compatible homebrew launcher/flashcart. Physical DS hardware must be tested separately from emulator verification.
TypeScript game + SDK declarations
|
typecheck + ES5 compilation
|
gen/game.js (same bytes)
/ \
browser API adapter embedded C byte array
Canvas + WebAudio |
Duktape + native API
libnds / ARM9 + ARM7
|
build/nds-ts-demo.nds
The TypeScript compiler runs on the development computer. The DS executes the generated ES5 JavaScript in Duktape. Screen drawing, buttons, touchscreen sampling, and audio output are native C++/libnds operations. Duktape is included in the source tree, with its own license and a documented platform configuration.
The initial game format is a single global script defining game. A minimal
example is:
var x = 120;
var game: NDSGame = {
update: function () {
x = Math.max(0, Math.min(240, x + nds.input.dx() * 2));
if (nds.input.hit('a')) nds.audio.tone(660, 6);
},
draw: function () {
nds.top.clear(0xffffff);
nds.top.sprite('orb', x, 138);
nds.bottom.clear(0xffffff);
nds.bottom.text('HELLO FROM TYPESCRIPT', 12, 12, 0x202020);
}
};
The compiler includes sdk/index.d.ts automatically. For editor completion in the
example folder, the provided demo also has a reference to that declaration file.
init() is optional; update() and draw() are required. Callbacks receive
this = game on both targets.
To use another entry file, run these commands from this directory:
npm run build:script -- examples/my-game/main.ts # JS and native headers only
npm run build -- examples/my-game/main.ts # Compile and build ROM
The browser previews the last generated gen/game.js. Rebuild the script after
editing TS; Vite reloads that generated file. npm run dev compiles the default
example before starting the preview.
The complete declarations are in sdk/index.d.ts.
| API | Behavior |
|---|---|
nds.width, nds.height | 256 and 192, for each display |
nds.top, nds.bottom | clear(color), rect(x,y,w,h,color), text(value,x,y,color), sprite(name,x,y) |
nds.input.down/hit/up(button) | Held, pressed this tick, released this tick |
nds.input.dx()/dy() | Direction in -1, 0, 1; opposite buttons cancel |
nds.touch | x, y, down, pressed, released; bottom-screen coordinates |
nds.audio.tone(hz, frames, volume?) | 40–4000 Hz, 1–600 whole ticks, volume 0–1; default 0.3 |
nds.frame | Simulation tick counter, beginning at 0 |
nds.stats | Native JS heap/current peak bytes and previous update/draw microseconds |
Button names: up, down, left, right, a, b, x, y, l, r, start,
select. Colors are integer 0xRRGGBB values. Drawing coordinates are rounded to
the nearest pixel and clipped. Negative/zero rectangle dimensions draw nothing.
Text uses an original 3×5 font: printable ASCII plus newline, uppercase rendering,
4-pixel character advance, and 7-pixel line advance. Text is limited to 1024 bytes
per call. The only bundled sprite is the original 16×16 orb, positioned by its
top-left corner. Sprite corners are transparent.
Browser heap metrics are reported as zero because browsers do not expose the Duktape allocator. Browser update/draw timings describe the browser adapter, not DS CPU costs. Tone generation is a single voice on both targets.
examples/ holds four games. dual-screen is the default demo measured below; the
others use the same API harder:
| Example | What it shows |
|---|---|
hinge-breakout | Bricks on the top screen, the paddle on the bottom, and a ball that crosses the hinge gap. |
touch-synth | A 16-step square-wave sequencer played from the touchscreen. |
pixel-paint | 16×12 pixel art drawn with the stylus and framed on the top screen. |
Build any of them into a ROM with npm run build -- examples/<name>/main.ts. So far only
dual-screen has emulator measurements. npm test plays every example for a minute of
random input and fails if a frame exceeds the 1500-quad top-screen budget.
site/ is the project's landing page. It runs every example on a browser console that
follows the native renderer's rules (RGB15 colors, the 3×5 font, the 1500-quad top-screen
budget and the script error screen). Visitors can edit a game and recompile it in the
browser under the same ES5 checks as tools/build-script.ts. It is live at
https://nds-ts.vercel.app, built on Vercel from vercel.json.
npm run dev:site # http://localhost:5175
npm run build:site # dist/site
npm run check # Tooling/SDK typecheck and ES5 game compilation
npm test # Compiler + actual compiled game behavior
npm run test:tools # ROM measurement/header/audio checks; Python + Pillow
npm run test:native # Real Duktape/native renderer; system C/C++ compiler
npm run build:web # Production browser preview
Native host tests use AddressSanitizer and UndefinedBehaviorSanitizer by default;
use SANITIZE=0 npm run test:native when the local compiler lacks sanitizer support.
They exercise the actual compiled demo, rendering/input/audio callbacks, script
exceptions, malformed SDK state, throwing getters, infinite-loop watchdogs, and
heap exhaustion.
For end-to-end DS verification, install Pillow and supply an already installed melonDS-compatible libretro core. This tool downloads no emulator or firmware:
python3 -m pip install Pillow
python3 -B tools/verify-rom.py build/nds-ts-demo.nds --core /path/to/melonds_libretro.so
The check validates the ROM header, measures movement and jumping from captured
pixels, checks touchscreen relocation and non-silent audio, and reads the runtime
metrics printed on the bottom screen. Evidence is saved in captures/demo/.
The included demo was verified with the melonDS 0.9.3 libretro core:
| Measurement | Result |
|---|---|
| Observed game rate | 59.9 ticks/second |
| JS heap shown by the HUD | About 82 KiB |
| Update / draw time | About 0.91 / 12.38 ms |
| Jump tone | 660.5 Hz (requested 660 Hz) |
| Touch relocation | Passed; visible within 3 emulated frames |
The upper GPU display is pipelined, so captured pixels trail the current game state. ROM checks allow this presentation delay while requiring the simulation to advance at the core's approximately 60 Hz rate. These results describe this demo in an emulator; physical hardware has not yet been verified.
A second ROM changed only the demo's TypeScript movement multiplier from 2 to 3. Holding RIGHT for 30 ticks then moved the orb 90 pixels instead of 60. Both ROMs passed the same input, touch, audio, and frame-rate checks, and all native source SHA-256 hashes remained unchanged.
Map, Set, and Promise
are rejected. New TS syntax that can compile to ES5 may be used.npm run package:source # dist/nds-ts-source.tar.gz
The export contains only this package's source, license, dependencies lockfile,
and a SHA-256 file manifest. It refuses symlinks and unknown file types, and excludes
builds, screenshots, caches, original game files, and Git history. Extract it into
an empty directory to begin an independent repository. private: true prevents
accidental npm publication; it does not limit use under the MIT source license.
Engine code, demo artwork, and the bitmap font: MIT, see LICENSE.
Duktape 2.7.0: MIT, see vendor/duktape/LICENSE.txt and AUTHORS.rst.
BlocksDS/libnds and the build image remain separate build dependencies under their
respective licenses. This project is an independent homebrew tool and is not
affiliated with Nintendo.