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。 以下为已保存的摘录。
Een real-time Pokémon battle royale voor de browser, mobile first, in de stijl van Black/White. Er zijn twee modi: Battle Royale (12 trainers, laatste die overblijft wint) en Raid (alleen of samen tegen één enorme eindbaas). Beide kun je solo of met vrienden spelen.查看完整 README ↗
Een real-time Pokémon battle royale voor de browser, mobile first, in de stijl van Black/White.
Speel: https://stormbreak.app
Er zijn drie modi:
Op het home-scherm kies je eerst de modus en dan hoe je speelt: online, solo/CPU of met vrienden.
Na een korte uitleg vul je je naam in en kies je: solo tegen bots, of samen met vrienden. Je kiest een trainer en één partner-Pokémon uit een roster van 24 (te filteren op rol en op melee/ranged); in de wereld vang je er nog twee bij (max. 3). Daarna word je gedropt op een grote kaart met in totaal 12 trainers. Je Pokémon loopt achter je aan en vecht in real time. Versla en vang wilde Pokémon, raap Master Balls en items op en blijf binnen de zone. Wie als laatste trainer overblijft, wint.
npm install
npm run dev # http://localhost:5173 (ook bereikbaar via je LAN voor je telefoon)
npm run build # type-check + productie-build naar dist/
Vercel herkent het project automatisch als Vite-app (build: npm run build, output: dist).
| Actie | Mobiel | Toetsenbord |
|---|---|---|
| Lopen | Joystick: tik ergens op de linkerhelft | WASD / pijltjes, of houd de rechtermuisknop vast (lopen naar de cursor) |
| Aanval 1 | Tik = automatisch richten, vasthouden = blijven aanvallen, slepen = zelf richten, loslaten = vuren | Linkermuisknop (vasthouden = blijven schieten) |
| Aanval 2 / 3 / ultimate | Idem op de andere knoppen | Q / E / R, gericht op je cursor |
| Pokémon wisselen | Tik op een Pokémon in je team (linksboven) | F |
| Vangen (verzwakte wilde Pokémon) | VANG!-knop | Spatie |
| Master Ball / Potion / Revive | Itemknoppen | 1 / 2 / 3 |
| Pauze / game verlaten | ❚❚-knop of de terugknop van je telefoon (vraagt eerst om bevestiging) | Esc |
keys.ts).pad.ts)./duo/, bijvoorbeeld het onderscherm van de AYN Thor): kaart, baas of score, je team (tik = wissel), items, scorebord, pauze en de chat. Verbindt vanzelf met het spel in dezelfde browser; installeerbaar als eigen app ("Stormbreak Duo") op duo.stormbreak.app (eigen origin, dus los van de hoofdapp; een verborgen frame duo-bridge.html op www geeft de berichten door, want een BroadcastChannel werkt alleen binnen één origin). Opties → Tweede scherm probeert het via de browser op het andere scherm te zetten (duo.ts, ui/duoView.ts).<audio>-element met media session in plaats van direct naar de speakers. Standaard uit; Auto = aan zolang een tweede scherm verbonden is. Op de AYN Thor hielp het niet: Chrome dempt daar al het geluid zodra beide schermen een Chrome-venster hebben.data/difficulty.ts).Zit je naast iemand? Dan heb je zo een potje:
In het potje zelf kun je ook chatten via de 💬-knop (op desktop: Enter).
Na afloop ga je terug naar de lobby voor een rematch, of kijk je mee tot het potje klaar is. Valt iemand weg, dan neemt een bot die trainer over.
Hoe het technisch werkt: de telefoons praten rechtstreeks met elkaar via WebRTC; PeerJS helpt ze alleen elkaar te vinden. Er is dus geen eigen gameserver nodig.
Je naam en een willekeurige speler-id worden op je toestel bewaard (src/profile.ts). Een account/inlog kan dat later vervangen.
Lokaal testen zonder internet: start een eigen PeerJS-server (npx peer --port 9000) en open de game met ?peer=127.0.0.1:9000.
Net als in Pokémon Unite heeft elke partner een rol en een aanvalsstijl. Je ziet ze bij de stats op het keuzescherm en kunt erop filteren. De rol geeft een klein voordeel; evoluties houden de rol van hun lijn, en wilde Pokémon krijgen een rol op basis van hun stats.
| Rol | Bonus | Partners |
|---|---|---|
| Aanvaller | +10% schade | Pikachu, Charmander, Bulbasaur, Gastly, Abra, Shinx, Deino |
| Allrounder | +5% schade, +7% HP | Eevee, Tepig, Oshawott, Gible, Axew, Machop, Dratini, Beldum |
| Verdediger | +15% HP, halve knockback | Squirtle, Larvitar, Munchlax, Mudkip |
| Snelheid | +12% loopsnelheid, 20% kortere cooldown op dash-aanvallen | Snivy, Riolu, Zorua, Scyther, Torchic |
Melee of Ranged volgt uit de basisaanval (de aanval die je het vaakst gebruikt).
Elke battle royale speelt in een van vijf werelden. In solo kies je die zelf, in multiplayer de host; standaard is het Willekeurig.
| Wereld | Wat is anders |
|---|---|
| Bos | Het klassieke groen met eiken, vijvers en dorpjes |
| Woestijn | Duinen, cactussen en droge struiken als verstopplek, een oase en zandstormen |
| Sneeuw | Besneeuwde dennen, bevroren meertjes en sneeuwval |
| Vulkaan | Asgrond, dode bomen, gloeiende lava in plaats van water en asregen |
| Nacht | Het bos in het donker, met vuurvliegjes en een donkere rand om het beeld |
Elk potje heeft twee gebeurtenissen, tussen de legendarische Pokémon door. Beide krijgen een banner, een pijl bovenin en een marker op de minimap.
Een duel tussen twee trainers in een stadion, best of 3.
Stadions: een rechthoekig wedstrijdveld met witte lijnen, een middencirkel, trainervakken en een Poké Ball in het midden. Eromheen staan een muur met reclameborden en tribunes vol publiek. Jouw kant heeft de ene clubkleur, de tegenstander de andere. Het publiek doet een wave, springt af en toe op en juicht als een ronde beslist is. Elke indeling is gespiegeld, zodat beide spelers hetzelfde veld hebben.
Solo en in een lobby kies je een stadion of Willekeurig. Testen kan met ?stadium=<id>.
Kracht: beide partners zijn volledig geëvolueerd op Lv 50 met alle vier de aanvallen, net als in een raid. Het gaat om skill en de match-up van types en rollen. HP herstelt niet vanzelf.
Rondes: wie de Pokémon van de ander verslaat, wint de ronde. Daarna begint de volgende met volle HP vanaf de startplekken, na een aftelling van 3 seconden. Wie eerst twee rondes wint, wint het duel.
Tijdslimiet in plaats van een storm: een ronde duurt maximaal 75 seconden. Is de tijd op, dan wint wie relatief de meeste HP over heeft. Bij gelijke stand wordt de ronde opnieuw gespeeld. De klok staat in de duel-balk en wordt rood in de laatste 10 seconden.
Power-ups: ze liggen op drie plekken, de eerste na 6 seconden en na het oppakken 14 seconden later weer:
Het middelste plekje geeft vaker X Attack of een Hyper Potion.
Spelen:
Een raid is PvE: jij (en tot 11 vrienden) tegen één legendarische baas, in een eigen arena. Er is geen storm en er zijn geen bots of wilde Pokémon. De baas is een verrassing: hij wordt willekeurig gekozen (nooit twee keer dezelfde na elkaar) en je ziet hem pas op het laadscherm.
Standaard is een raid een dungeon, in de geest van WoW-dungeons: eerst vecht je je door een reeks zalen, en pas aan het eind gaat de poort naar de arena van de legende open. In het raidmenu kies je de dungeon of Klassiek (meteen de arena in, willekeurige baas). Er zijn drie dungeons (src/data/dungeons.ts, logica in src/game/dungeon.ts, art in src/game/dungeonArt.ts), en ze gaan op volgorde open: versla er een om de volgende te ontgrendelen (op een preview of localhost kun je een dichte dungeon toch kiezen):
Elke dungeon heeft een thema (theme in de data: type, kleuren, relieknamen, teksten voor HUD en laadtips) en een eigen intro en outro (H3-video's in public/cutscenes). De Stormtoren en de IJscitadel hergebruiken de art van de Diepten, omgekleurd na het bakken, plus eigen sprites (src/assets/dungeon/props-*.png).
Groepen en pulls: in elke zaal staan groepen vijanden klaar (sommige patrouilleren). Kom je binnen 5,5 tegel of raak je er een, dan komt de hele groep op je af, en een gekoppelde groep doet mee (overpull). De poort uit een zaal (basalt plaat met gloeiende runen) gaat pas open als alles erin verslagen is.
Rollen in een groep (symbool op het naamplaatje): ⚔ brute (meer HP, slaat hard, trager), ✦ caster (houdt afstand, cast een vuurbal: rode cirkel onder je met castbalk), ✚ healer (geneest de zwakste uit de groep, 30%), ◆ schildwacht (vijanden binnen 4,5 tegel nemen 40% minder schade; gele stippelcirkel). Elites (★) zijn groter en taaier.
Interrupts: een vijand met een castbalk breek je met een melee-, dash- of ultimate-treffer, of met twee treffers van wat dan ook: de spreuk mislukt ("Onderbroken!").
Aggro / tank: vijanden gaan op wie hen het meest schade deed; schade van een Verdediger telt ×3, van een Allrounder ×1,3.
Wachters: Magmortar (kegel, Levende Bom die een speler volgt en een magmapoel achterlaat, vuurballen, hittegolf) en Camerupt (uitbarstingsring, aardbeving, Magmavloed: poelen die 9 s blijven branden). Ze roepen hulp bij 60/30% HP en worden na 2 min (Camerupt 2:10) woedend (sneller, harder). Een wachter lokt bij de pull de rest van de zaal mee.
Buit: een verslagen wachter geeft het team een reliek (Sintel van de Vlam: +15% schade; Pantser van de Vulkaan: −15% schade), +1 leven en een Potion per speler.
Laatste Bastion: een gauntlet van 3 waves; daarna gaat de arenapoort open en ontwaakt Reshiram zodra iemand de krater in loopt (gewone raid, 4 minuten).
Levens en checkpoints: 3 levens voor de hele run; neer = na 10 s terug bij de laatste poort. Levens op? Als je team een zaal verovert ben je terug met één leven. Een veroverde zaal geneest 15%.
Types: dungeonvijanden doen en krijgen tussen 0,75× en 1,5× typeschade, zodat geen partner je erdoorheen sleept.
Schaal: meer spelers = grotere groepen (+50% per speler) en meer HP voor wachters; moeilijkheid past aantallen, levels, schade en de enrage-timer aan.
Testen: ?boss=reshiram|zekrom|kyurem&room=N start die dungeon in zaal N (poorten ervoor open; room=6 = voor de arena), ?classic=1 slaat de dungeon over.
Jouw team: je partner is in de raid volledig geëvolueerd en Lv 50 met alle vier de aanvallen (Pikachu wordt Raichu, Charmander Charizard, enzovoort). Je hebt 2 Potions en HP herstelt niet vanzelf. Er verschijnen wel geregeld Potions in de arena.
| Baas | Arena | Wat de omgeving doet | Signature-aanvallen |
|---|---|---|---|
| Reshiram | Vulkaankrater | Lavascheuren branden als je erop staat; uit vier kraters spuit lava (Uitbarsting) | Blue Flare (kegel), Fusion Flare (meteoren), Hittegolf, Vuurring, en in fase 3 Cross Flame: draaiende vlammenstralen |
| Kyurem | IJsgrot | De vloer is glad, waardoor je doorglijdt; ijspilaren geven dekking en breken na drie treffers | IJsadem (bevriest je), Icicle Crash, Dragon Pulse, Glaciate, Vriesgolf, en in fase 3 Blizzard: de hele arena, behalve achter een pilaar |
| Zekrom | Stormtop | Vier bliksemafleiders blokkeren je pad en schieten om de paar seconden stroom naar elkaar: sta niet tussen twee masten | Bolt Strike (inslagen uit een donderwolk), Fusion Bolt (Zekrom raast over de lijn), Discharge, Donderring, en in fase 3 Onweer: inslagen over de hele arena en alle afleiders tegelijk |
| Rayquaza | Hemelpilaar | Het oude stenen dak van de toren, met mos, gebroken pilaren en open lucht als rand; wervelwinden trekken door de arena en doen schade zolang je erin staat | Dragon Ascent (vliegt op en landt op een speler), Outrage (drie lijnen), Draco Meteor, Hurricane (tornado's), en in fase 3 Delta Stream: harde wind die iedereen één kant op duwt |
| Mewtwo | Psychisch lab | Het vloerraster laadt op: de helft van de vakken (dambordpatroon) slaat toe, dus ga op tijd naar een donker vak | Psystrike (kegel), Shadow Ball, Teleport (verschijnt naast je en slaat om zich heen), Psychische ring, en in fase 3 twee klonen die de aanvallen meedoen |
Nieuwe bazen zijn vooral data: een rij in src/data/bosses.ts met hun aanvallen, vormen en uiterlijk per fase, plus eventueel een arena in src/game/world.ts.
Sprites en animaties van de bazen
scripts/bake-boss-sprites.py zet de geanimeerde BW-sprites (GIF) om in sprite sheets (src/assets/boss/<id>.png) met frametijden (src/data/bossAnims.ts). Nieuwe vorm erbij: zet het id in de lijst en draai het script opnieuw.scripts/bake-ai-anim.py maakt van een AI-animatie een pixel-art actie (zoals de brul bij een fasewissel). Werkwijze: zet de sprite 6× vergroot op een effen greenscreen (#00b140; magenta #ff00ff voor groene Pokémon zoals Rayquaza), animeer die met MiniMax H3 (startframe = eindframe, vaste camera), en draai het script. Dat haalt de achtergrond weg, schaalt terug naar spritegrootte en zet elke pixel op het palet van de echte sprite. Resultaat: src/assets/boss/<id>-<actie>.png en src/data/bossActions.ts.src/synth.ts): pulse-lead, marimba, synthbas, strijkers, drums en galm. Er zijn nummers voor het titelscherm, het menu, de battle royale (versnelt in de finale), de raid-baas (versnelt in de laatste fase), overwinning en nederlaag. Twee alternatieve sets staan in src/data/soundtracks.ts. Plus Pokémon-cries via PokéAPI.src/moveSfx.ts): de klank van het type, de vorm van de aanval en zwaarder naarmate de aanval sterker is. Geluiden van anderen komen uit de goede richting en worden zachter op afstand. Items (potion, revive, ballen, oppakken) hebben ook hun eigen geluid. Raid-bazen hebben een eigen, zwaardere set: elke aanval zwelt aan tijdens de waarschuwing en slaat in met een diepe dreun over de hele arena, plus geluid voor de dash, het opstijgen en neerkomen, de teleport, de klonen, tornado's en Delta Stream, de bliksemafleiders, lavagaten, het vloerraster en brekende ijspilaren. De baas brult bij de start, de nieuwe fase klinkt als een ontlading en zijn nederlaag als een instorting.src/assets/voice/, afgespeeld door src/voice.ts) roept het titelscherm, het aftellen, de storm, legendarische Pokémon, K.O.'s, raid-fases en winst of verlies om. De muziek gaat even zachter terwijl hij praat.src/i18n.ts).Gasten en accounts gebruiken dezelfde regels (api/_progress.ts). Een gast bewaart zijn voortgang in de browser. Bij de eerste Discord-login wordt die eenmalig (met limieten) overgezet naar het account. Alleen accounts komen in de ranglijst.
REWARD_ROAD in api/_progress.ts; de signature-aanvallen in SIGNATURE in src/data/moves.ts.Spelers verbinden rechtstreeks met de host (WebRTC). Op mobiele data en achter strenge routers lukt dat alleen via een doorgeefserver (TURN). De gratis TURN-servers van PeerJS bestaan niet meer, dus de game haalt ze op via /api/ice:
CF_TURN_KEY_ID (Turn Token ID) en CF_TURN_API_TOKEN (API Token) in Vercel.TURN_URLS (komma-gescheiden), TURN_USERNAME, TURN_CREDENTIAL.https://www.stormbreak.app/api/auth/callback.DISCORD_CLIENT_ID en DISCORD_CLIENT_SECRET en deploy opnieuw.
Het gebruikt dezelfde Upstash Redis als de stats. Zonder deze variabelen is de vriendenkaart onzichtbaar.Voor spelers: op het home-scherm staat een 📰-knop, met een rode stip zolang er een update is die je nog niet zag. Terugkerende spelers krijgen een nieuwe update één keer vanzelf te zien. Nieuwe spelers niet: voor hen telt de huidige update als gezien.
Een update toevoegen: zet bovenaan NEWS in src/data/news.ts een nieuw blok. Het blok krijgt:
id die hoger is dan de vorige (de datum werkt prima, zoals 2026-11-02);['English', 'Nederlands'];items met elk een icoon en een tekst.Alles wat je nog niet zag staat open (de nieuwste altijd). Wat je al zag, is ingeklapt onder "Eerdere updates".
Video (optioneel, alleen bij grote updates):
public/news/.video: { wide: '/news/naam-16x9.mp4', tall: '/news/naam-9x16.mp4' }.De game kiest zelf:
Eén van de twee is ook genoeg. Gebruik MP4 (H.264 + AAC) van ongeveer 10 tot 20 MB.
poster: { wide: '/news/naam-16x9.jpg', tall: '/news/naam-9x16.jpg' }.Voor trailers en update-video's: een tijdelijk profiel dat alleen in dat tabblad bestaat. Er wordt niets opgeslagen, er gaat niets naar de server en het telt niet mee voor de ranglijst.
?showcase: alles vrij (level 50, alle prestaties, shiny voor elke partner).?showcase=boost: hetzelfde, en in solo-potjes (battle royale en raid) start je Pokémon meteen volledig geëvolueerd op Lv 25 met alle vier de aanvallen. Handig voor legendaries en signature-ultimates.?showcase=12 (elk level 1–49): je bent level 12, net onder 13. Je volgende potje geeft een level-up, en de bijbehorende unlock als dat level er een heeft. Bijvoorbeeld ?showcase=43 → Groudon.?showcase=off, of het tabblad sluiten: terug naar normaal./stats. Het wachtwoord wordt één keer per tabblad bij de server gecontroleerd./stats is een los paneel met anonieme tellingen: wie er nu online is (menu, lobby, battle royale of raid), spelers per dag en per maand, nieuwe spelers, potjes per modus, speeltijd, drukte per uur, populaire partners, bazen met hun winstpercentage, werelden, uitslagen, apparaat, taal en bronnen. Deel je link met ?via=naam (bijv. stormbreak.app/?via=tiktok) en die bron telt apart.
api/t.ts (Vercel Function); api/stats.ts levert ze aan het paneel. Opslag in Upstash Redis. Per apparaat een willekeurige id (niet je speler-id), geen namen, geen IP-adressen. Op localhost en het lokale netwerk wordt niets verstuurd; in het paneel kun je je eigen apparaat uitzetten.STATS_KEY = je eigen wachtwoord; daarna opnieuw deployen. Zonder deze instellingen doet de game niets met stats en toont /stats deze stappen.src/
data/ Pokémon, aanvallen, types, trainers, werelden (themes.ts), raid-bazen (bosses.ts)
game/ wereldgeneratie, engine, bot-AI, renderer, aanvalseffecten (vfx.ts),
raid-baas en telegrafen (boss.ts), BR-gebeurtenissen (events.ts)
net/ multiplayer: rooms (PeerJS), protocol, state-sync tussen host en spelers
ui/ titel, uitleg, menu, lobby, keuzeschermen, HUD, cutscenes, resultaten (DOM boven de canvas)
music.ts chiptune-sequencer en soundtrack
panel/ het stats-paneel (/stats)
i18n.ts Engels en Nederlands
stats.ts anonieme events voor het stats-paneel
profile.ts je naam en speler-id (later te vervangen door een login)
api/ Vercel Functions: t.ts (events in), stats.ts (paneel-data)
Pokémon-sprites (Gen V Black/White), item-sprites en trainersprites (BW-battle-art, ook gebruikt in de wereld) worden tijdens het spelen geladen van PokéAPI/sprites en Pokémon Showdown. Ze staan dus niet in deze repo. Pokémon en alle bijbehorende namen en art zijn © Nintendo / Game Freak / The Pokémon Company. Dit is een niet-commercieel fanproject.
De wereld en alle aanvalseffecten worden in code getekend.
Progressie:
Code:
src/game/duel.ts: rondes, tijdslimiet en power-ups;src/data/stadiums.ts: de stadions;src/game/world.ts: indeling en tekenwerk (generateStadium, paintStand, paintField);src/game/render.ts: het bewegende publiek (drawCrowd);src/game/ai.ts: de CPU.Ontwijken: elke grote aanval zie je eerst als rode vorm op de grond die langzaam volloopt: een cirkel, kegel, lijn of ring. Sta je erin als hij vol is, dan kost dat een groot deel van je HP. Elke waarschuwing is lang genoeg om eruit te lopen als je meteen reageert.
Fases: op 66% en 33% HP wordt de baas woedend. Dat is een korte cinematic: de camera zwenkt naar de baas, de wereld wordt donker, hij brult (een eigen animatie), en op een flits met schokgolf verschijnt zijn nieuwe vorm. Hij brult iedereen weg, krijgt nieuwe aanvallen en valt sneller aan, en er vallen Potions.
Elke fase voelt anders: een eigen kleur over het scherm, een pulserende rand (in de laatste fase op het ritme van een hartslag), meer weer en een arena die escaleert: hitte uit de vloer, sneeuwstormvlagen, onweer dat de lucht verlicht, windstrepen of een vervormende werkelijkheid. De baas gloeit in de kleur van zijn fase.
Laatste fase, nieuwe vorm: Kyurem wordt Black Kyurem (ijs + bliksem: Freeze Shock, Fusion Bolt), Rayquaza wordt Mega Rayquaza (Extreme Speed), Mewtwo wordt Mega Mewtwo Y (Aura Sphere). Reshiram gaat over op blauw vuur (Dragon Rush, Blauwe Vlammenstorm) en Zekrom op Teravolt (Teravolt-sprong: springt op en landt op je).
Animatie: de bazen spelen hun echte geanimeerde Black/White-sprites af, zweven (Rayquaza, Mewtwo) of stampen, en laten nabeelden achter bij een dash.
Levens en tijd: iedereen heeft één revive: ga je neer, dan kom je na 10 seconden één keer terug aan de rand. De tweede keer kijk je mee. De raid mislukt als iedereen op is of na 4 minuten. Met meer spelers heeft de baas meer HP.
Afloop: "Raid geslaagd!" of "Raid mislukt" met je tijd, je aandeel in de schade en je levens.
api/match.ts (start/einde/titel/shiny) en api/rank.ts (ranglijst). Alles staat in dezelfde Upstash Redis.