- Add two airports (north/south) with full geometry: runways, taxiways,
aprons, terminals, hangars, stands, and helipads; walkable airport
grounds extend beyond city bounds.
- Introduce ATC AI agent ("Torre de Controle City10") using AI_ATC_MODEL
to generate takeoff clearances; includes dispatch endpoint with
30-second cooldown and deterministic fallback on failure.
- Implement AI model fallback chain: preferred model → AI_FALLBACK_MODEL
before failing, applied in ChatController and PersonTalkController.
- Add luminous sign labels (letreiros) for plazas, beach, food, hospital,
school, city hall, and airports with day/night glow.
- Fix city presence cache: compute is_me per viewer instead of baking
into shared per-second cache to prevent cross-user flag leakage.
- Add tests: AirportTest, CityPresenceTest, SignLabelsTest, and
PersonTalkTest fallback model retry scenario.
15 KiB
Executable File
City10 — Cidade 3D Virtual com Agentes de IA
City10 é uma plataforma full-stack de simulação urbana 3D com agentes de inteligência artificial, construída sobre Laravel 13 e Three.js. O visualizador3D é jogável no navegador: trânsito semafórico, pedestres, agentes (Prefeito, lojistas), conversas de rua com IA, praças com academia e uma praia com lazer. O raciocínio dos NPCs acontece através da API OpenRouter.ai, restrito a uma lista de modelos gratuitos.
Plataforma operada pela Syspanel — Santa Rita do Sapucaí/MG, Brasil. Contato: contato@syspanel.com.br · WhatsApp: (35) 99226-1684 · www.syspanel.com.br
Visão Geral da Arquitetura
| Camada | Tecnologia | Responsabilidade |
|---|---|---|
| Backend / Painel Admin | Laravel 13 (PHP ≥ 8.3) | Autenticação, API REST, regras de negócio, consentimento LGPD |
| Banco de Dados | MariaDB (MySQL) | Persistência de usuários, lojas, agentes, conversas e consentimentos |
| Cache / Fila | Database (sessões/cache/jobs) | Sessões, cache, agendamentos e throttle |
| Frontend 3D | Three.js | Mundo jogável no navegador (cidade, trânsito, praia, clima) |
| Tempo Real | Polling HTTP + SSE | Presence (~2,5 s), chat (~2,5 s) e stream de resposta de NPC (SSE) |
| Cérebro dos Agentes | OpenRouter.ai | Raciocínio dos NPCs e conversas com modelos gratuitos |
Fase 1 — Plataforma (Entregue)
- Estrutura Laravel 13 com autenticação diferenciada (Admin / Usuário Comum).
- Migrations: usuários com
role, lojas com coordenadas 3D (pos_x,pos_y,pos_z), agentes de IA e trilha de consentimento legal (LGPD). - API REST (Sanctum) para usuários, lojas, agentes, cidade e documentos legais.
- CAPTCHA matemático próprio (soma), sem dependências externas, nos formulários públicos.
- Multi-idioma: Português (Brasil), Inglês e Espanhol — selecionável pelo usuário.
- Termos de Uso, Política de Privacidade e Política de Cookies (LGPD), versionados e com aceite auditável (data, hora, versão, IP).
- Banner de cookies com link para os Termos de Uso e Privacidade.
- Página inicial responsiva (desktop e smartphone).
Fase 2 — Mundo 3D Jogável (Entregue)
O visualizador /city carrega o mundo completo em tempo real:
- Cidade de 72 quarteirões (grade 9 × 8 de blocos de 40 m; bounds
−120..160 × −120..120), com rio e ponte a oeste, extensão rodoviária ao sul, hospital, escola, prefeitura e casas de jogadores. - Trânsito: carros, motos, bikes e ônibus com tráfego à direita, loop por quarteirão e semáforos por cruzamento (fases NS/EW com amarelos e all-red; veículos param na linha de parada antes das faixas).
- Faixas zebradas reais (barras longitudinais paralelas ao fluxo, design MUTCD) com calçadas e meio-fios interrompidos nas travessias — 323 faixas no layout atual.
- Pedestres com travessia sincronizada ao semáforo; bloqueio de travessia do jogador no vermelho.
- Praças (1 a cada 4 células) com academia externa: exercícios com pose, efeito em saúde/energia e missão “Shape em dia”.
- Praia a leste (
/city+App\Support\Beach): areia, mar com ondas animadas (deslocamento de vértices), espuma na orla, banhistas, nadadores, surfistas, salva-vidas (torre + patrulha), quadra de basquete com jogadores e bola em arremesso, barracas de comidas, cadeiras e guarda-sóis. O jogador pode relaxar na areia (teclaE→POST /city/actions/beach), recuperando energia/saúde por tick até o máximo. - Dois aeroportos derivados dos bounds (pavimento + sinalização de
pista com designadores, taxiways com eixo amarelo, pátio de embarque com
posições de estacionamento de aeronaves, terminal com pontes articuladas,
hangars, torre de controle e helipista): 7 aeronaves de 7 companhias
(jato comercial, jato regional, monomotor e helicóptero) executam o ciclo
completo taxi → decolagem → cruíse sobre a cidade → aproximação → pouso
→ taxi → gate, com contagem de decolagens/pousos em
stats().flights. - Torre de controle com IA: o agente
atc"Torre de Controle City10" (modeloAI_ATC_MODEL,poolside/laguna-xs-2.1:free) gera clearances de decolagem a cada decolagem (POST /city/airport/dispatch, cooldown de 30 s) numa cadeia de modelosAI_ATC_MODEL→ default →AI_FALLBACK_MODEL(xiaomi/mimo-v2.6-flash), com texto determinístico quando tudo falha; o clearance mais recente aparece como aviso "✈ ...". - Agentes vivos: prefeito itinerante, lojistas nas lojas, pedestres com rotas, mais trens (passagem de nível com barreiras), ônibus/trem embarcáveis, avião e barcos no rio.
- Dia/noite e clima com ciclo de horas, névoa, chuva e sombras que seguem o jogador.
- Conversas de rua com outros jogadores e NPCs (ver próxima seção).
- Performance: batching estático por material, sombra seguindo o jogador (janela ±120), lâmpadas/rodas com LOD por distância e fachadas a 256 px — medições ~30–60 fps numa GTX 770.
Controles
| Controle | Ação |
|---|---|
W A S D |
Andar (A/D = lateral) |
| Mouse (pointer lock) | Olhar; arrastar na cena quando sem lock |
← → |
Viram a câmera (não andam de lado) |
| Joystick virtual (mobile) | Vertical = andar, horizontal = virar a câmera |
E |
Contexto: exercício na praça / relaxar na praia / parar |
Espaço |
Pular |
| Clique num NPC | Abrir chat |
| Chegar perto de alguém | Chat abre sozinho; sai de perto ele fecha |
Conversas de Rua (/talk/person) e IA por Personagem
- Registro por dia: cada fala gravada em
person_talks(from/tode character ou agent +talked_on+is_fallback), consultável viaGET /talk/person?kind=agent|character&peer=ID. - Fio da meada: o histórico completo (dias anteriores + hoje) é enviado
como contexto nas respostas de IA — placeholders de erro (
is_fallback) ficam visíveis na UI mas nunca entram no contexto do modelo. - Quem responde:
- Par com humano vivo (sessão tocada nos últimos 5 min) → relay puro, nunca é substituído por IA;
- Par sem humano (cidadãos demo, NPCs) → persona anônima de morador responde via OpenRouter, sem dados cadastrais no payload.
- Resposta de IA é gerada after-response (não depende de worker de
fila), com espaçamento por par, allow-list de modelos, fallback localizado
em falha e auditoria em
last_decision. - Identidade por personagem: colunas em
characters—ai_model,ai_age,ai_gender,ai_personality,ai_bio(persona injetada no prompt; recém-criados já nascem com personalidade/idade). - Modelo por personagem (ordem de resolução, sempre validado em
allowed_models): colunaai_model→ mapaAI_CHARACTER_MODELS(id ou nome) → slot determinístico do poolAI_MODELS→AI_DEFAULT_MODEL.
Requisitos
- PHP ≥ 8.3 (com
pdo_mysql,mbstring,curl,zip,gd,bcmath) - Composer 2
- MariaDB ≥ 10.6 (ou MySQL ≥ 8.0)
- Node.js ≥ 18 (apenas para assets Vite/Tailwind, opcional na Fase 1)
- Docker (opcional, para o ambiente
dockercity10)
Instalação
1. Dependências PHP
composer install
2. Configuração do ambiente
cp .env.example .env
php artisan key:generate
Edite o .env e configure o banco de dados:
DB_CONNECTION=mariadb
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=<sua_senha>
3. Chave do OpenRouter.ai e modelos
A chave não é versionada. Insira-a apenas no .env local:
OPENROUTER_API_KEY=<sua_chave>
AI_DEFAULT_MODEL=deepseek/deepseek-v4-flash-0731
# Pool de modelos gratuitos distribuídos deterministicamente entre os
# personagens (cada um mantém o próprio modelo estável).
AI_MODELS=deepseek/deepseek-v4-flash-0731,nvidia/nemotron-3.5-lightning:free,liquid/lfm-2.5-2.6b:free,openrouter/free,nvidia/nemotron-3-ultra-550b-a55b:free
# Override por personagem: "nome ou id=modelo" separado por vírgula.
AI_CHARACTER_MODELS=
# AI_ATC_MODEL: default model of the control-tower agent (airport
# clearances: takeoff authorizations). Must be allow-listed.
AI_ATC_MODEL=poolside/laguna-xs-2.1:free
# AI_FALLBACK_MODEL: tried when the preferred model of a call fails
# (owner-approved paid model with near-zero cost).
AI_FALLBACK_MODEL=xiaomi/mimo-v2.6-flash
4. Banco de dados
php artisan migrate --seed
5. Servidor de desenvolvimento
php artisan serve --port=16980
A aplicação ficará disponível em http://localhost:16980.
Ambiente Docker (dockercity10)
O container dockercity10 já expõe a aplicação na porta do host 16980
(container :80, Apache + PHP-FPM) e o MariaDB na porta 16981. Após clonar
o projeto em /app (bind-mount), rode as migrations dentro do container:
docker exec -it dockercity10 bash -c "cd /app && php artisan migrate --seed"
Contas de Teste (ambiente de desenvolvimento)
| Papel | Senha | |
|---|---|---|
| Administrador | marcocosta@gmx.com |
Mega886ax |
| Usuário Comum | user@sistema.net |
User123 |
⚠️ Estas credenciais são exclusivas para desenvolvimento. Altere-as ou remova-as (
php artisan db:seed --class=UserSeederapós ajustar) antes de qualquer implantação em produção.
Testes
php artisan test # suíte completa (PHPUnit)
./vendor/bin/pint # formatação de código
Destaques da suíte (testes de recurso): autenticação/LGPD, ações da cidade
(exercício, posição com clamp até a orla da praia), social, mercado,
missões, conversas de rua (PersonTalkTest — histórico multidiário,
resolução de modelo, ausência de PII no payload) e lazer na praia
(BeachLeisureTest — geometria no payload, efeitos e zona).
Estrutura de Endpoints da API
Base URL: http://localhost:16980/api (Bearer Sanctum)
Públicos
| Método | Rota | Descrição |
|---|---|---|
| GET | /auth/captcha |
Gera desafio matemático (necessário para login/registro) |
| POST | /auth/login |
Autentica e emite token Sanctum |
| POST | /auth/register |
Cria conta de usuário comum |
| GET | /legal/documents |
Lista a versão atual dos documentos legais |
Autenticados (Bearer token)
| Método | Rota | Descrição |
|---|---|---|
| GET | /auth/me |
Perfil + status de consentimento |
| PATCH | /auth/profile |
Atualiza nome, idioma ou senha |
| POST | /auth/logout |
Revoga o token atual |
| GET | /city/world |
Snapshot da cidade (lojas + agentes com coordenadas 3D) |
| GET/POST | /stores |
Lista/cria lojas |
| GET/PUT/DELETE | /stores/{id} |
Gerencia uma loja (dono ou admin) |
| GET | /stores-world/seed |
Mundo de lojas (seed 3D) |
| GET | /legal/status |
Status de aceite dos documentos |
| POST | /legal/accept |
Registra o aceite (auditoria LGPD) |
| GET | /legal/history |
Histórico de consentimentos do usuário |
Somente Administrador
| Método | Rota | Descrição |
|---|---|---|
| CRUD | /api/users |
Gestão de usuários |
| CRUD | /api/agents |
Gestão de agentes de IA |
| GET | /api/agents-meta/models |
Lista os modelos gratuitos permitidos |
| GET | /api/agents-world/seed |
Mundo de agentes (seed 3D) |
| GET/POST | /stores, /citizens, /cities, /world |
Admin web (aprovação de cidadãos, cidades, mundo) |
Rotas Web da Cidade (sessão de navegador)
Todas exigem login + termos aceitos.
| Método | Rota | Descrição |
|---|---|---|
| GET | /city |
Visualizador 3D (HTML + bundle Three.js) |
| GET | /city/data |
Payload do mundo: layout, lojas, agentes, praças, prédios, beach |
| GET | /city/presence |
Cidadãos online (posições, is_me) — throttle 60/min |
| GET/POST | /talk/person |
Conversas de rua: histórico/contexto e envio (throttle 120 e 30/min) |
| POST | /city/actions/position |
Sincroniza posição (clamp até a orla da praia) |
| POST | /city/actions/{action} |
Ações: eat, drink, sleep, wake, work, study, buy, sell, build, apply-job, exercise, stop-exercise, beach, ride, accident… |
| POST/GET | /city/chat/{agent} (+/stream) |
Conversa com NPC (envio + SSE de resposta) |
| POST/GET | /city/messages/{character} |
Mensagens assíncronas entre personagens |
| POST | /city/social/{verb} · GET /city/social/inbox |
Amizade, casamento, filho, inbox |
| GET | /city/airport |
Sites dos aeroportos, torre (ATC) e clearance atual |
| POST | /city/airport/dispatch |
Pede um clearance de decolagem à torre (cooldown 30 s) |
| GET/POST | /city/market (/buy, /sell) |
Mercado |
| GET/PUT | /city/customize |
Personalização do personagem |
Modelos de IA Permitidos
Somente os modelos abaixo podem ser usados (validado no backend em
config/ai.php; os quatro últimos foram verificados ao vivo no catálogo do
OpenRouter). Exceção aprovada pelo responsável: xiaomi/mimo-v2.6-flash
(pago, custo mínimo ~1,4e-7/token, verificado ao vivo) — usado como
fallback de todas as cadeias de chamada:
poolside/laguna-m.1:free cohere/north-mini-code:free
deepseek/deepseek-v4-flash-0731:free qwen/qwen3.8-27b:free
nvidia/nemotron-3-ultra-550b-a55b:free nvidia/nemotron-3-super-120b-a12b:free
google/gemma-4-31b-it:free google/gemma-4-26b-a4b-it:free
openai/gpt-oss-20b:free nvidia/nemotron-nano-12b-v2-vl:free
nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free
nvidia/nemotron-3-nano-30b-a3b:free nvidia/nemotron-nano-9b-v2:free
poolside/laguna-xs-2.1:free inclusionai/ling-3.0-flash-vl:free
qwen/qwen3.7-flash:free
deepseek/deepseek-v4-flash-0731 nvidia/nemotron-3.5-lightning:free
liquid/lfm-2.5-2.6b:free openrouter/free
xiaomi/mimo-v2.6-flash (fallback — ver nota acima)
Segurança e Conformidade (LGPD)
- Senhas armazenadas com bcrypt (cast
hashed). - Tokens de API (Sanctum) revogáveis por usuário.
- RBAC: papéis
admin/usercom middleware dedicado. - CAPTCHA matemático nos formulários públicos (login/registro).
- Consentimento auditável: data, hora, versão do documento, IP e user-agent
gravados em
user_consents(imutáveis). - Banner de cookies com opção de aceitar/recusar cookies não essenciais.
- Direitos do titular (art. 18 LGPD): histórico de consentimentos disponível
ao usuário; contato para exercer direitos:
contato@syspanel.com.br. - IA sem PII: ao chamar o OpenRouter envia-se apenas contexto simulado da
cidade e o diálogo/identidade in-world — nunca e-mail, senha ou dados de
conta (regras em
RULES.md, seção 2).
Licença
Software Proprietário — © 2026 Syspanel. Todos os direitos reservados.
Veja o arquivo LICENSE para os termos completos de uso.
Bibliotecas de terceiros utilizadas são compatíveis com uso comercial
(por exemplo: Laravel — MIT; Three.js — MIT). O crédito aos autores originais
está registrado em RULES.md.
Contato
- E-mail: contato@syspanel.com.br
- WhatsApp: (35) 99226-1684
- Site: www.syspanel.com.br
- Localização: Santa Rita do Sapucaí — Minas Gerais — Brasil
© 2026 — Todos os direitos reservados — Powered by Syspanel — www.syspanel.com.br