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를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Party games for people sitting at the same table. Most of them are played on
a single phone, passed around (pass-and-play); Quiplash is played on
everybody's phone at once, in a room they join with a four-letter code.
No accounts, runs entirely in the browser, and works offline as an
installable PWA (Quiplash's rooms are the one thing that needs a network).README 전문 보기 ↗Party games for people sitting at the same table. Most of them are played on a single phone, passed around (pass-and-play); Quiplash and Battleship are played on everybody's phone at once, in a room they join with a four-letter code — and on a single phone too, when there is only one. No accounts, runs entirely in the browser, and works offline as an installable PWA (the rooms are the one thing that needs a network).
Games included:
The interface is available in Italian and English.
Play it at https://edoconfo.github.io/GameHub/
npm install
npm run dev
Open http://localhost:5173/GameHub/ (the port is fixed).
npm run build # output in dist/
npm run preview # preview the build
The PWA icons are already generated in public/icons/. To regenerate them:
npm run icons
They are created by a plain Node script (scripts/gen-icons.mjs) with no dependencies.
Every push to main is deployed automatically by GitHub Actions.
main: the .github/workflows/deploy.yml workflow builds and publishes the site.https://<user>.github.io/GameHub/.The app is served from a subfolder (the repository name), so
vite.config.js sets:
const BASE = '/GameHub/'
If you rename the repository, change BASE to /<new-name>/ (keep the leading and trailing slashes).
When a new version is deployed, the app notices and offers to update.
Word packs are per game: each game has its own packs, in its own format and storage. The global settings only handle theme, language and players.
To manage them, open a game → Manage words. There you can switch packs on and off,
create your own (saved in the browser's localStorage) and edit or delete them.
A pack holds one list per language, side by side. A pack without the current language is hidden.
No game ships its words. They all live in a Supabase database (schema in
supabase/): the app only reads them, downloads them the first time
it sees a network, keeps them on the phone in IndexedDB so they play offline, and
offers to update them when the database copy changes. The public key in
src/shared/supabase.js is read-only by design — the
database's own rules allow it nothing else.
Until that first download there is nothing to play with, and the game says so instead of showing an empty list.
The built-in packs are played but not opened: their words stay out of sight, so nobody at the table has read them first. Packs you write yourself are yours to edit, and sit beside them.
Each item is a pair: the Civilians' word and a similar word for the
Undercovers. There is one built-in pack, Base, in the mw_base table.
It used to be five themed packs. Picking one told the table what the word was about, which hands Mister White — the one player without a word — most of the answer. A pool with no theme gives nothing away.
Each item is one word (or name, or phrase), and the built-in packs are the
categories: Animali, Cibo & Bevande, Film & Serie, VIP & Personaggi, Da mimare.
They live in two tables, hu_packs (the categories and their names) and
hu_words (the words in them).
The categories stay, where Mister White's themes went away, because here the category is the game: you pick "Animali" and everyone knows it.
In both tables one row carries every language at once, and no column may be empty — so a pair or a word exists in all languages or in none, and every language plays the same list, with the same count.
Each item is one prompt — "The worst name for a cat" — and there is one
built-in pack, Base, in the ql_prompts table. Like Mister White's Base it
is played but not opened: a prompt read beforehand is a prompt somebody has
already written the answer to.
The shared logic (storage, enabling, custom packs, languages) lives in
src/shared/packStore.js: a createPackStore factory
that each game instantiates with its own namespace and a codec describing the
shape of its items. The editor UI (src/shared/packEditor.js)
is shared, but it is opened from inside each game, not from the settings.
Each game is a self-contained module. The rest of the app (hub, router, settings) knows nothing about it.
Create src/games/<id>/index.js with a default export (the game contract):
export default {
id: 'my-game',
name: 'My Game',
description: 'One line for the hub card.',
icon: '🎲',
glyph: 'words',
menu: [{ title: 'Play', sub: '', phase: 'play', glyph: 'play' }],
mount(container, ctx, phase) {
// ctx = { storage, players, table, stats, router, root, applyTheme }
// render into container; return a cleanup function if needed
// (called when leaving the game: stop timers and sensors)
}
}
The full contract, including the optional shared table, is documented in
src/games/registry.js.
Register it in src/games/registry.js:
import myGame from './my-game/index.js'
export const games = [misterWhite, headsUp, myGame]
That's it: the game shows up in the hub and #/my-game works.
src/
main.js boot + routes
router.js hash router (#/, #/<game>, #/<game>/<phase>, #/players, #/settings)
styles.css theme tokens + shared UI
shared/ storage, i18n, players, table, pack store + editor, PWA update, Supabase client
hub/ home, players, shared table scene
games/
registry.js list of games
mister-white/ engine + match + packs.js (Base from Supabase)
heads-up/ match (teams, turns) + screens + motion + teams.js + packs.js
quiplash/ round.js (the arithmetic) + game.js (a match, as the room
holds it) + room.js / guest.js (several phones) +
match.js (one phone) + screens.js + packs.js
battleship/ engine.js (the rules) + game.js (a match, both fleets) +
room.js (two phones) + local.js (one phone) + screens.js
supabase/ database schema for the remote packs
Quiplash is the one game here that is better on more than one device: writing is private and simultaneous, which a single phone can only imitate by taking turns. So it has a room.
The wire is src/shared/realtime.js: Supabase
Realtime in broadcast mode. Messages go phone → Supabase → phones and are
never written down — no table, no rows to clean up, and the public key still
cannot read or change a single row of the database. Broadcast and not the
database's own change feed, because a party game is judged on how fast it
answers.
The room is as private as its code: anybody who knows it can join, and everything the room says is readable by anyone in it who opens a browser console. It is a game among friends, not a bank.
Battleship has no word packs: the sea is the whole game. It is played the way
Quiplash is, with the same wire (src/shared/realtime.js,
on a channel of its own):
game.js): it
knows where both fleets are, so it calls every shot. The other phone is only
ever sent its own view — its fleet, the shots at it, what its own shots
found — and the other fleet ship by ship as it sinks.The fleet is the classic one (5, 4, 3, 3, 2) on a 10×10 sea, ships never touch, and a hit fires again.