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,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
Jogo de crash (iGaming) com cara de desenho animado dos anos 30. Um biplano decola, o multiplicador sobe, o dia vira noite estrelada… saque antes que ele caia. Protótipo com créditos de demonstração. O resultado de cada rodada e o saldo são calculados no navegador. Antes de qualquer uso com dinheiro real, leia Antes de usar com dinheiro real. • O jogo • Rodando o projeto • Comandos • Arte gerada por IA • Som • Como o código é organizado • Ajustes rápidos • Antes de usar com dinheiro real • Créditos e licença檢視完整 README ↗
Jogo de crash (iGaming) com cara de desenho animado dos anos 30. Um biplano decola, o multiplicador sobe, o dia vira noite estrelada… saque antes que ele caia.
[!WARNING] Protótipo com créditos de demonstração. O resultado de cada rodada e o saldo são calculados no navegador. Antes de qualquer uso com dinheiro real, leia Antes de usar com dinheiro real.
Cada rodada tem três fases:
e^(0,085·t): 2× em ~8 s, 10× em ~27 s). Clique em CASH OUT (ou aperte Espaço) para sacar a aposta × multiplicador.A margem da casa é de 3%: a chance de o voo passar de x é 0,97 / x (até 1.000×). O histórico de rodadas fica no topo e a "arquibancada" mostra jogadores fictícios apostando junto.
O que dá vida ao visual
| Parallax | 5 camadas de cenário (montanhas, colinas, árvores, cerca, arbustos) em velocidades diferentes; o chão afunda conforme o avião sobe. |
| Dia → noite | O multiplicador guia a hora do dia: pôr do sol por volta de 2,5×, lua e estrelas a partir de ~4× e noite plena em 8×. O sol "vira" a lua, estrelas piscam e cenário/nuvens fazem cross-fade para versões noturnas desenhadas. |
| Filme antigo | Pós-processamento com granulado, vinheta, viragem sépia, riscos, poeira, tremidinha a 12 fps e transição de íris entre rodadas. |
| Avião | Hélice animada quadro a quadro (com disco de borrão em alta rotação), squash & stretch "rubber hose" e, na queda, a hélice sai voando. |
| Som | Ragtime e jazz dos anos 20/30, motor de biplano, projetor de filme, buzina "a-ú-ga", "ka-ching", fanfarra de circo, grilos e coruja à noite. |
| Aposta feita, esperando a decolagem | Saque no pôr do sol |
|---|---|
| Noite estrelada | A queda |
As capturas são geradas por npm run screenshots (com o npm run dev rodando).
Precisa de Node.js 20.19+ ou 22.12+ (exigência do Vite 8; desenvolvido com o 24).
npm install
npm run dev
Abra o endereço que o Vite mostrar (por padrão http://localhost:5173).
No celular: rode npm run dev:mobile e abra no celular o endereço "Network" (mesma rede Wi-Fi). O som destrava no primeiro toque e funciona mesmo com o iPhone no silencioso. Acrescente ?audiodebug na URL para ver o estado do áudio no canto da tela (running · 12/12 sons · música tocando = tudo certo).
As artes e os sons já vêm prontos no repositório; os passos de arte e som abaixo só são necessários para gerar ou trocar algum.
| Comando | O que faz |
|---|---|
npm run dev | Servidor de desenvolvimento |
npm run dev:mobile | Mesmo servidor, aberto para a rede local (celular) |
npm run build / npm run preview | Build de produção em dist/ e prévia dele |
npm run assets | Gera as artes que ainda não existem (OpenRouter, ver abaixo) |
npm run assets:all | Gera o que faltar, na ordem certa: o avião primeiro e o resto com ele como referência de estilo |
npm run assets:plane-no-prop | Apaga a hélice desenhada de um avião antigo (a hélice é animada à parte) |
npm run audio | Trata os sons de art/audio-src/ e gera public/audio/ (precisa de ffmpeg e ffprobe) |
npm run screenshots | Refaz as capturas deste README com um Chrome sem janela (rode junto com npm run dev) |
Toda a arte vem do Nano Banana (google/gemini-2.5-flash-image) via OpenRouter, com o script scripts/generate-assets.mjs.
cp .env.example .env # coloque sua OPENROUTER_API_KEY
npm run assets:all # gera o que faltar
Como o pipeline funciona
sharp (flood fill a partir das bordas, vãos internos, bordas suavizadas e "desmistura" da cor), recorta e salva o PNG. Imagens com fundo errado são recusadas em vez de virar asset.art/raw/, então dá para reprocessar sem pagar de novo (--rekey).--ref) para os objetos; céu e cenário vão sem referência para o modelo não copiar o avião neles.skyNight, mountainsNight etc. repintam a imagem do dia (mesma composição, outra luz), o que permite cross-fade perfeito no jogo. Se a imagem do dia mudar, o script avisa que a variante ficou desatualizada.art/preview.png mostra todos os assets sobre fundo liso para conferir recortes.npm run assets -- plane sun # só os assets citados
npm run assets -- --force # regera (sobrescreve)
npm run assets -- --skip plane # tudo menos os citados
npm run assets -- --ref art/raw/plane.png
npm run assets -- --rekey # refaz a remoção de fundo a partir de art/raw (sem custo)
npm run assets -- plane --rekey --flop # espelha (ex.: avião veio virado para a esquerda)
npm run assets -- plane --edit "..." # edita a imagem existente com o modelo
npm run assets -- --dry-run # mostra os prompts sem chamar a API
Os prompts descrevem o estilo "rubber hose dos anos 30" sem citar personagens ou jogos existentes. Se um asset não existir, o jogo usa uma versão desenhada em código (o céu vira um gradiente), então roda mesmo sem arte gerada. As exceções são sunDusk e as variantes *Night do cenário e das nuvens: sem elas, o sol, o cenário e as nuvens continuam com a imagem do dia durante a noite.
Sons e músicas do Pixabay (Pixabay Content License: uso comercial, crédito não obrigatório). Lista completa com autores e links em art/audio-src/SOURCES.md.
| Momento | Som |
|---|---|
| Espera / dia | Playlist "Silent Movie" (charleston em disco antigo) + "Silent Movie" (ragtime ao piano), com cross-fade |
| Noite | "Night Jazz", entrando aos poucos com o céu escurecendo, + grilos e uma coruja |
| Fundo | Projetor de filme rodando, bem baixo |
| Contagem / botões | Bloco de madeira / tecla de máquina de escrever |
| Decolagem / voo | Buzina "a-ú-ga" / motor de biplano (o tom sobe com o multiplicador) |
| Aposta / saque | Moeda / caixa registradora "ka-ching" (+ fanfarra de circo a partir de 5×) |
| Queda | Explosão de desenho + apito descendo |
Para trocar um som: substitua em art/audio-src/ o arquivo indicado no campo src da tabela SOUNDS de scripts/process-audio.mjs (ou aponte o src para o novo arquivo) e rode npm run audio (ou npm run audio -- engine para tratar só um, pelo campo name). Para um som novo, acrescente uma entrada em SOUNDS e toque-o em src/audio.js; só colocar o arquivo na pasta não basta.
O script corta silêncios, normaliza o volume, monta loops sem emenda e grava o volume real no manifest (o jogo compensa o que o limitador tirar). O mix fica em MIX, em src/audio.js.
No celular, o áudio é feito para não dar problema: os sons já baixam e decodificam enquanto o jogo carrega, destrava no primeiro toque em qualquer lugar (até na tela de carregamento) e sai nesse mesmo toque, toca no modo silencioso do iPhone, devolve o áudio do aparelho quando o jogo está no mudo (sua música de outro app volta a tocar), descarta sons enquanto o sistema interrompe o áudio (em vez de tocar tudo junto depois) e toca as músicas em streaming para economizar memória.
[!NOTE] As músicas estão registradas no Content ID do YouTube. Isso não afeta o jogo, mas trailers e gameplays postados lá podem receber reivindicação automática (contestável com a licença do Pixabay).
flowchart LR
game["game.js<br/>rodada, apostas, saques"] -- eventos --> main["main.js<br/>liga tudo, loop por frame"]
main --> scene["scene.js<br/>Three.js: céu, parallax,<br/>curva, avião, partículas"]
main --> ui["ui.js<br/>painel de apostas (DOM)"]
main --> audio["audio.js<br/>efeitos, loops, música"]
textures["textures.js<br/>PNGs gerados ou reserva"] --> scene
film["filmShader.js<br/>filme antigo + íris"] --> scene
config["config.js<br/>regras e ajustes"] --> game & scene
├── index.html, src/
│ ├── main.js liga jogo, cena, painel e som
│ ├── game.js máquina de estados da rodada (espera → voo → queda)
│ ├── scene.js mundo Three.js (câmera ortográfica, camadas, curva, avião, ciclo dia/noite)
│ ├── filmShader.js pós-processamento de filme antigo
│ ├── textures.js carrega public/assets (+ versões procedurais de reserva)
│ ├── draw.js utilitários de canvas (letreiro com contorno, starburst)
│ ├── audio.js som (Web Audio + streaming de música)
│ ├── ui.js, style.css painel de apostas
│ └── config.js números do jogo e do visual
├── public/
│ ├── assets/ PNGs do jogo + manifest.json (gerados)
│ └── audio/ MP3s do jogo + manifest.json (gerados)
├── art/
│ ├── raw/ imagens cruas do modelo (para --rekey)
│ ├── audio-src/ sons originais do Pixabay + SOURCES.md
│ └── preview.png folha de prévia das artes
├── scripts/
│ ├── generate-assets.mjs arte com OpenRouter + Nano Banana
│ ├── process-audio.mjs tratamento de áudio com ffmpeg
│ └── capture-screenshots.mjs capturas do README (Chrome sem janela)
└── docs/screenshots/ imagens deste README
Quase tudo que se quer mexer está em src/config.js:
| Bloco | Exemplos |
|---|---|
CONFIG | margem da casa, velocidade do multiplicador, duração das fases, saldo inicial (os textos "House edge: 3%" e "Refill 1,000" do rodapé ficam fixos em index.html: atualize junto) |
PARALLAX, CLOUDS | altura, velocidade e profundidade de cada camada de cenário |
PLANE | tamanho do avião, posição/velocidade da hélice, borrão |
DAY_CYCLE | em que multiplicador começa o pôr do sol e a noite, número de estrelas |
Em desenvolvimento, window.__bb expõe game, world, textures, sfx e hud no console para inspeção.
Este repositório é um protótipo de jogo e de visual. Para operar como produto de apostas:
crypto.getRandomValues) e o saldo fica no localStorage.art/audio-src/SOURCES.md.