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.