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 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
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çaREADME 전문 보기 ↗
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.