prancheta
Demo 1 jogável do simulador de carreira Prancheta, com LaLiga, elencos reais e partida 2D.
Prancheta — Demo 3.1
Versão integrada do simulador local de carreira de técnico, com a temporada espanhola 2026/27. O projeto usa Next.js App Router exclusivamente com arquivos .js.
O que funciona
A seed identifica uma carreira e deixa o salvamento preparado para uma futura associação com a conta autenticada do jogador.
Demo jogável 0.3.0
Esta versão fecha a revisão da Demo 3. Os dez problemas abaixo foram corrigidos e cobertos por regressão; as descrições preservam a causa original para facilitar futuras revisões do motor.
✅ 1. Substituição não rouba mais gol ou cartão de quem saiu
app/match-engine.js → buildPlayerStats e applyDiscipline
Gols e cartões são guardados como índice de posição (scorerSlot,
card.slot) e resolvidos contra a escalação atual. Como a súmula é
reconstruída a cada substituição, trocar um jogador reatribui tudo o que ele fez
para quem entrou no lugar dele.
Medido numa partida real do jogo:
gol do mandante aos 50', slot 10
antes da substituição: Nico Serrano (1)
substituindo Nico Serrano -> Álvaro Djaló
depois da substituição: Álvaro Djaló (1)
o substituído segue na súmula? NÃO
O mesmo acontece com cartão amarelo, e aí a suspensão por acúmulo cai no jogador errado. Consequências:
- artilharia da carreira fica errada;
- quem sai perde tudo o que fez e desaparece da súmula;
- quem entra herda gols, cartões e ainda ganha
starts: 1eminutes: 90; - um gol de cobrança manual desaparece de
playerStatsse o cobrador for substituído depois (applyManualGoalsprocura porplayerId).
Direção: guardar playerId no evento em vez do índice do slot, e separar
"quem começou jogando" de "quem está em campo agora".
✅ 2. Pênalti manual conta uma única vez nas estatísticas
app/components/MatchCenter.js → liveStats
overriddenActionIds é aplicado só na narração (duas vezes, sobre
timeline.events). O monta direto de
, sem esse filtro — e está nas listas
e . Então o lance roteirizado continua contando junto com a cobrança
manual: , e o xG vira em vez de .
Falta direta não sofre disso: o lance roteirizado é do tipo foul, que não entra
em isShot.
Direção: passar overriddenActionIds para liveStats e filtrar playedActions.
✅ 3. Jogadores permanecem dentro do campo
app/match-engine.js → getMatchFrame
Os ajustes de marcação, apoio e posse (moveToward, e a posição do portador da
bola) não têm limite de campo — só a forma do bloco em responsiveShape é
limitada. Quando a bola sai de jogo, quem persegue vai atrás dela para fora do
gramado. Medido numa partida (amostragem de 1 s):
| lance | invasão máxima |
|---|---|
| shot_wide | 5,0 m |
| goal | 5,0 m |
| counter | 4,0 m |
| foul | 3,8 m |
| corner | 3,7 m |
| shot_save | 2,7 m |
| throw_in | 1,5 m |
O campo vai de 0 a 105; o pior caso desenhou um jogador em x = -5,0.
✅ 4. Motor emergente recalibrado
app/tactics-sim.js — amostra de validação completa, soma dos dois times:
| modelo | real | |
|---|---|---|
| finalizações no alvo | 10,25 de 27,75 (37%) | ~32% |
| gols | 3,25 | ~2,7 |
| finalizações | 27,75 | ~25 |
| passes | 1.074 | ~900 |
| escanteios | 8,5 | ~10 |
| impedimentos | 2,75 | ~4 |
| faltas | 21,5 | ~22 |
O motor agora distingue chute no alvo de bola apenas tocada pelo goleiro, possui faltas, tiros livres, amarelos e vermelhos, e usa intervalos de decisão e finalização calibrados para evitar sequências artificiais.
✅ 5. A bola permanece no quadro final da cobrança
app/components/SetPieceStage.js → useFlightClock
Ao entrar na fase result o cronômetro para e zera elapsed, então struck
volta a ser falso e a bola é redesenhada no ponto da falta. Fica atrás do painel
de resultado, que é 74% opaco — dá para perceber. Direção: congelar o último
quadro do voo em vez de zerar o cronômetro.
✅ 6. Jogadores de times opostos também respeitam colisão
app/match-engine.js → separatePlayers roda uma vez para cada time, então um
mandante e um visitante podem ocupar o mesmo ponto. Medido: 21 pares a menos de
0,6 m um do outro numa partida.
✅ 7–10. Robustez e acabamento
Rodar localmente
Requer Node.js 22 ou superior.
npm install
npm run dev
O servidor de desenvolvimento usa http://localhost:3000.
Validar
npm test
Os nomes, escudos e plantéis são usados apenas neste protótipo pessoal. O projeto não é afiliado à LALIGA, RFEF, clubes ou atletas. Overalls, condição física, valores e simulações são dados próprios do jogo.