Skip to content

Repository files navigation

YUDDHA

Guerra territorial em tempo real sobre a Terra.

Yuddha (युद्ध) — "guerra" em sânscrito.

SvelteKit Svelte Three.js globe.gl License


Uma única página, sem barras de rolagem: o planeta é a interface. Qualquer visitante assiste ao mundo vivo — mísseis balísticos saindo da atmosfera, frotas contornando continentes, territórios mudando de cor — mas só quem entra reivindica um território e joga.

Conceito

  • O mundo é dividido em 1.924 territórios: uma grade recortada pelas fronteiras reais, mais os 645 municípios de São Paulo com nomes verdadeiros (malha do IBGE).
  • Ao entrar, o jogador assume um território livre — por GPS, clique no globo ou sorteio — e cresce dali: vilarejo → município → comarca → província → estado → nação → império.
  • Jogadores não têm nome: cada um é uma cor. Sem chat, sem texto livre, sem apelido. Só ações no mapa.
  • O jogo não termina. Quando uma cor perde o último território, ela colapsa e outra nasce no lugar. O tabuleiro nunca esvazia.
  • Tudo viaja em velocidade real. Um ICBM cruza 10.000 km em ~26 minutos de jogo; uma esquadra leva dias atravessando o Atlântico; uma coluna de infantaria leva horas até o vizinho. A barra superior tem um acelerador de 1× a 7200× para isso caber no seu tempo de tela.

Como rodar

npm install
npm run dev

Abre em http://localhost:5173. Esc fecha painéis e cancela a mira, H abre a ajuda.

Comando O que faz
npm run dev servidor de desenvolvimento
npm run build build de produção
npm run check svelte-check + TypeScript
npm run geo:sp baixa os 645 municípios de SP do IBGE
node scripts/build-cells.mjs regenera a grade mundial de territórios

Como jogar

  1. Entrar e assumir um território livre.
  2. Construir — o centro cívico destrava tudo; fazendas e minas produzem; armazém aumenta o teto.
  3. Recrutar — o quartel abre blindados, o porto abre a marinha, a base aérea abre aviões e mísseis de cruzeiro, o silo abre balísticos.
  4. Enviar — escolha a unidade e clique no alvo. O grupo viaja na velocidade da unidade mais lenta.
  5. Conquistar — vencer a batalha rende saque. Para anexar é preciso levar um emissário e zerar a lealdade do alvo.

Defesa: muralha aumenta o poder defensivo, radar antecipa o aviso, e a bateria antimíssil dispara interceptadores automaticamente. Diplomacia: até 3 alianças por cor, pacto de não-agressão, e ruptura que só vale depois de 24 h de jogo — não existe traição instantânea.

Sob o capô

Simulação (src/lib/game/)

  • Determinística. Toda a aleatoriedade sai de um PRNG semeado e toda mutação passa por engine.dispatch(order) — a mesma costura que um servidor autoritativo vai usar.
  • Posição é função do tempo. posição = f(t), sem replay: quem abre a página no meio de um ataque vê o míssil exatamente onde ele deveria estar.
  • Economia preguiçosa. Produção, manutenção e lealdade são materializadas na leitura, não por tick — 1.924 territórios custam quase nada por quadro.
  • 34 cores de IA, cada uma com personalidade (agressão, economia, marinha, tecnologia, lealdade) que decide construção, recrutamento, ofensiva e diplomacia, com limite logístico de unidades fora de casa.

Movimento

Domínio Como a rota é calculada
Terra A* sobre a malha de adjacência real (fronteira compartilhada); atravessar território inimigo custa 2,6×
Mar A* sobre uma máscara terra/mar rasterizada no carregamento — as frotas contornam continentes e preferem mar aberto à costa
Ar Grande círculo, com subida e descida nas pontas do voo
Balístico Grande círculo com perfil de apogeu: 280 km no MRBM, 1.250 km no ICBM

A bateria antimíssil resolve numericamente o ponto de encontro (busca binária sobre a trajetória do alvo) e lança um interceptador que cruza a rota no instante certo.

Combate

Dados estilo War (3 × 2, empate favorece a defesa) definindo a sorte que multiplica cada poder; artilharia derruba níveis de muralha antes do cálculo; perdas do vencedor crescem com o quão apertada foi a batalha. Armas combinadas: um grupo leva infantaria, blindados, artilharia e emissário juntos.

Globo (src/lib/globe/)

  • Shader próprio de dia/noite usando normal de mundo — o terminador não depende da posição da câmera. O horário solar é o real: o lado escuro do globo é onde é noite agora.
  • Relevo derivado do mapa topográfico, especular só no oceano, faixa quente no pôr do sol, franja atmosférica, nuvens em rotação e bloom opcional.
  • LOD: longe são os 177 países agregados pela cor dominante; perto, no máximo 460 células dentro do horizonte, re-extrudadas só quando a câmera assenta.
  • Unidades são objetos Three.js de verdade (não arcos estáticos), com rastro em cometa, pool de objetos, materiais em cache e teto de 420 desenhadas.

Desempenho

Medido com 1.924 territórios e ~250 unidades em movimento: 0,79 ms por quadro em média, pior quadro 32 ms (troca de LOD). Em 6,7 dias de jogo simulados: 1.784 batalhas, 462 lançamentos, 143 conquistas, 163 interceptações, 27 alianças.

O motor nunca entra em $state. Proxiar milhares de objetos a 60 fps mataria o desempenho — em vez disso a UI observa um contador (hud.tick) e relê do motor o que precisa.

Estado atual

O jogo roda inteiro no cliente. Cada visitante vê o mesmo mundo inicial (mesma semente) e a mesma história enquanto a aba está aberta — ainda não é um mundo compartilhado entre pessoas. O caminho para isso já está desenhado:

  1. Subir o schema de docs/04 no Supabase (Postgres + PostGIS).
  2. Mover Engine.step() para uma Edge Function com pg_cron — o servidor vira dono do relógio e do RNG.
  3. Trocar engine.dispatch(order) local por RPC; o cliente só envia intenção.
  4. Assinar territories / units / events via Realtime e alimentar o mesmo store.svelte.ts.

Nada disso muda a camada visual: o globo já consome o motor por uma interface única.

Estrutura

src/lib/game/        rng · geo (esférica + rotas navais) · config (balanço)
                     world (geração) · engine (simulação) · ai · combat · store
src/lib/globe/       globeScene (camadas + LOD) · globeMaterial (shaders)
                     unitsLayer · sun
src/lib/components/  painéis da interface
scripts/             geração dos dados geográficos
static/geo/          fronteiras e territórios (TopoJSON/GeoJSON)
static/textures/     Blue Marble, Black Marble, topografia, nuvens, céu
docs/                documentos de design

Deploy

Importe o repositório no Vercel — o framework SvelteKit é detectado sozinho (adapter-auto) e não precisa de nenhuma variável de ambiente. O build é estático (ssr = false, prerender = true).

Documentação de design

Doc Conteúdo
01 — Visão e Conceito Pitch, pilares, público, o que o jogo não é
02 — Game Design Regras: spawn, recursos, tropas, combate, lealdade, diplomacia
03 — Arquitetura Fluxos, tempo real, anti-cheat
04 — Banco de Dados Schema SQL (PostGIS), RLS, funções, jobs
05 — Mapa e Territórios Fontes geográficas, pipeline, GPS
06 — Globo e Visual Camadas do globe.gl, LOD, UI sem scroll
07 — Android (PWA/TWA) Manifest, service worker, Play Store
08 — Roadmap Fases M0 → M5 e o que já está feito

Créditos dos dados

Fronteiras Natural Earth via world-atlas · malha municipal IBGE · texturas NASA Visible Earth (Blue Marble e Black Marble) · ícones Bootstrap Icons.

Licença

MIT.

About

Jogo de guerra territorial em tempo real sobre um globo 3D realista. SvelteKit 5, Three.js e globe.gl.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages