Cel mai greu lucru la un joc în browser nu e să-l construiești — e să-l vadă cineva. Site-ul tău pornește de la zero trafic; portalurile de jocuri (CrazyGames, Poki, GameDistribution) au deja zeci de milioane de jucători și împart cu tine veniturile din reclame, de obicei în jur de 50%. Concluzia la care am ajuns cu Neon Arcade: site-ul propriu e platforma, portalurile sunt distribuția — și ai nevoie de amândouă. Articolul acesta descrie exact cum livrăm același joc în ambele lumi dintr-un singur codebase, fără două versiuni de întreținut.
De ce nu poți urca pur și simplu build-ul de pe site
Portalurile au reguli stricte, iar cele două care schimbă arhitectura sunt:
- Fără linkuri externe. Jocul rulează în iframe-ul lor și nu are voie să trimită jucători în afară — nici către site-ul tău, nici către pagini de privacy proprii. Butonul nostru „înapoi la arcade" trebuie să dispară complet din build-ul de portal.
- Fără monetizare proprie și fără conturi terțe. Pe site vindem jetoane prin Stripe și ținem progresul în Firebase. În portal, ambele sunt interzise: monetizarea se face exclusiv prin SDK-ul portalului (reclame recompensate), iar progresul stă în localStorage.
Deci ai nevoie de două build-uri cu comportamente diferite la fiecare punct de contact cu banii și cu identitatea — dar dintr-un singur cod, altfel îți dublezi costul de mentenanță pentru totdeauna.
Arhitectura build-ului dual
Soluția noastră, cu Vite și TypeScript, are trei piese:
1. Un flag de compilare
Build-ul de portal se face cu o variabilă de mediu (PORTAL=crazygames npx vite build) care setează un define global. Tot codul poate întreba IS_PORTAL la compile-time, iar bundlerul elimină ramurile moarte — build-ul de portal nici măcar nu conține codul de Stripe sau Firebase.
2. Module interschimbabile
Punctele de contact sensibile — portofelul de jetoane și navigarea către hub — trăiesc în module cu aceeași interfață publică, în două variante: wallet.ts / wallet-portal.ts, back-to-arcade.ts / back-to-arcade-portal.ts. Un plugin de Vite face schimbul la build. Restul jocului nu știe și nu-i pasă în ce lume rulează: cere „deblochează personajul", iar dedesubt asta înseamnă fie o tranzacție de jetoane pe server, fie o reclamă recompensată prin SDK-ul portalului.
3. Curățenia HTML-ului
Același plugin șterge din index.html al build-ului de portal linkurile de privacy/terms și orice navigare externă, și șterge fișierele aferente din output. Înainte de orice submisie rulăm un „purity check" simplu:
grep -c "firebase\|numele-domeniului-tau" dist-crazygames/assets/*.js
# trebuie să afișeze 0
Dacă grep-ul găsește ceva, build-ul nu pleacă. E un test de trei secunde care ne-a scutit de respingeri.
Adaptorul de SDK: o singură interfață pentru toate portalurile
Fiecare portal are SDK-ul lui, dar toate vor cam aceleași semnale. Le-am ascuns după o interfață unică — pe site toate funcțiile sunt no-op, în portal deleagă către SDK-ul real:
portalInit()la pornire șiloadingStop()când apare meniul — portalurile își măsoară timpul de încărcare și penalizează jocurile lente;gameplayStart()/gameplayStop()la granițele unei runde;midgameAd()între runde — niciodată înainte de prima rundă; prima impresie a jucătorului nu trebuie să fie o reclamă;rewardedAd(): Promise<boolean>pentru bonusuri alese de jucător — resurse extra, revive, deblocări;onAdMute(cb)— cerință de portal: audio-ul jocului trebuie tăiat pe durata reclamei.
Detaliu util pentru testare: SDK-ul CrazyGames rulează în mediu „local" când jocul e servit de pe localhost și simulează reclamele — vezi fluxul complet fără să fii publicat. Poți valida integrarea înainte de submisie.
Submisia: cum arată procesul pe fiecare portal
- CrazyGames — submisie deschisă, cel mai bun punct de start. Arhivezi conținutul folderului de build (index.html la rădăcina zip-ului), adaugi un cover 1920×1080, nume, descriere, categorie, controale. Review-ul durează câteva zile și e non-exclusiv.
- Poki — aplicație curatoriată; preferă jocuri proaspete, deci aplică devreme, nu după ce jocul e vechi. SDK propriu (încă un caz în adaptor). Acceptarea e selectivă, dar traficul merită.
- GameDistribution / itch.io — mai târziu: GD sindicalizează către sute de portaluri mici, itch e bun pentru prezență și feedback.
Economia: ce câștigi de fapt
Pe site-ul propriu păstrezi ~97% din vânzările directe, dar aduci singur fiecare jucător. Pe portaluri primești ~50% din veniturile din reclame, plăți lunare cu praguri mici, dar jucătorii vin singuri. Nu e o alegere — e o secvență: portalurile îți aduc volumul și numele, site-ul tău monetizează fanii. Build-ul dual e prețul tehnic al acestei strategii, și e surprinzător de mic odată ce arhitectura e la locul ei.
Checklist înainte de prima submisie
- Build de portal separat, cu flag la compile-time, nu cu if-uri la runtime.
- Zero Firebase / conturi / Stripe / linkuri externe în build-ul de portal — verificat cu grep, automat.
- SDK-ul portalului integrat prin adaptor: loading, gameplay, midgame, rewarded, mute.
- Nicio reclamă înainte de prima rundă.
- Progres în localStorage; jocul complet jucabil fără cont.
- Cover 1920×1080 + descriere + controale pregătite pentru formular.
- Fluxul de reclamă simulată verificat local înainte de upload.
Construiești un joc în browser și te gândești la distribuție? Jocurile noastre sunt pe games.hashcoreai.com, iar la contact@hashcoreai.com răspundem cu plăcere la întrebări despre proces.