{"id":51617619,"url":"https://github.com/dvduardo/sinaleiro","last_synced_at":"2026-07-12T15:02:08.953Z","repository":{"id":369786418,"uuid":"1291203488","full_name":"dvduardo/sinaleiro","owner":"dvduardo","description":"Recomenda sinais ferroviários para sua malha de trens no Satisfactory — direto no navegador, seu save nunca sai da sua máquina","archived":false,"fork":false,"pushed_at":"2026-07-07T00:23:45.000Z","size":5812,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-07-07T01:10:13.175Z","etag":null,"topics":["game","railways","satisfactory","satisfactory-community","satisfactory-helper"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dvduardo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-07-06T15:39:37.000Z","updated_at":"2026-07-07T00:23:49.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dvduardo/sinaleiro","commit_stats":null,"previous_names":["dvduardo/sinaleiro"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/dvduardo/sinaleiro","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvduardo%2Fsinaleiro","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvduardo%2Fsinaleiro/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvduardo%2Fsinaleiro/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvduardo%2Fsinaleiro/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dvduardo","download_url":"https://codeload.github.com/dvduardo/sinaleiro/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvduardo%2Fsinaleiro/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35394859,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-12T02:00:06.386Z","response_time":87,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["game","railways","satisfactory","satisfactory-community","satisfactory-helper"],"created_at":"2026-07-12T15:02:08.257Z","updated_at":"2026-07-12T15:02:08.948Z","avatar_url":"https://github.com/dvduardo.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Sinaleiro\n\n**No ar em https://dvduardo.github.io/sinaleiro/** · projeto aberto — [contribuições são bem-vindas](#contribuindo).\n\nAnalisa o save do seu mundo de **Satisfactory** e recomenda onde colocar sinais ferroviários — qual trilho, que lado, virado para onde — sobre o mapa real do jogo.\n\n- **Sinal de Trajeto** (Path) nas entradas de cada junção, virado para a junção.\n- **Sinal de Trecho** (Block) nas saídas, virado para fora — libera o bloco assim que o trem sai.\n- Modo **misto** (padrão): cada trilho é classificado automaticamente como mão única ou bidirecional — via dupla ganha um sinal por poste, via simples ganha o par completo, e pontas soltas em construção ficam de fora. Os modos manuais **bidirecional** e **mão única** continuam disponíveis.\n\nNo modo misto a classificação combina quatro evidências: trilhos-ponte do grafo não podem ser mão única (o trem não teria volta); pares paralelos seguem a regra da mão direita; a orientação da estação no save dá o sentido de atracação; e a geometria da agulha resolve desvios pendurados entre duas junções (um trem não faz curva fechada numa junção). Sem evidência nenhuma, o trecho é tratado como bidirecional — o par completo de sinais é sempre seguro.\n\n## Privacidade\n\nO site roda o analisador **inteiro no seu navegador** (Python via [Pyodide](https://pyodide.org/), em WebAssembly). **Seu save nunca sai da sua máquina** — não há upload, não há servidor.\n\n## Uso via linha de comando\n\nO pipeline também funciona como ferramenta local (Python 3.11+, sem dependências externas):\n\n```sh\npython3 src/report.py /caminho/para/Save.sav out --misto   # ou --mao-unica / --bidirecional\n# gera out/mapa_sinais.html (mapa interativo) e out/sinais_recomendados.txt (checklist)\n\npython3 src/web_api.py /caminho/para/Save.sav --misto       # payload JSON do site\npython3 src/classify.py /caminho/para/Save.sav              # só a classificação por trilho\n```\n\n## Rodando localmente\n\nPré-requisitos: [Node.js](https://nodejs.org/) 22+ (site) e Python 3.11+ (CLI e teste de paridade — sem nenhuma dependência pip).\n\n```sh\ngit clone https://github.com/dvduardo/sinaleiro.git\ncd sinaleiro/web\nnpm install\nnpm run dev     # abre em http://localhost:5173\n```\n\nO `npm run dev` já faz tudo: empacota `src/*.py` + `vendor/` para o Pyodide, prepara o mapa e sobe o Vite. Para testar, use um save seu (`%LocalAppData%/FactoryGame/Saved/SaveGames` no Windows) ou o botão \"veja uma malha de demonstração\" na landing — não precisa ter o jogo.\n\nOutros comandos úteis:\n\n```sh\nnpm run build   # build de produção em web/dist (tsc + vite)\nnpm run smoke   # teste de paridade: pipeline no Pyodide (Node) vs CPython\nnpm run demo    # regenera os payloads do modo demonstração (web/public/demo/)\n```\n\nOs payloads da demonstração (\"veja uma malha de demonstração\" na landing) são\n**commitados** — o CI não tem saves. Rode `npm run demo` e commite quando o\n`PAYLOAD_VERSION` de `src/web_api.py` mudar ou para trocar o save de exemplo\n(`npm run demo -- /caminho/para/Save.sav`).\n\n## Arquitetura\n\n```\nsave .sav ─▶ src/parse_save.py ─▶ src/graph.py ─▶ src/directions.py (mão única)\n                                       │          src/classify.py   (misto)\n                                       ▼\n                              src/signal_rules.py ─▶ recomendações\n                                       │\n                    ┌──────────────────┴──────────────────┐\n                    ▼                                     ▼\n             src/report.py (CLI:                   src/web_api.py (JSON\n             HTML + checklist)                     para o site / Pyodide)\n```\n\n- `src/` é a **fonte única** do algoritmo: o site empacota esses mesmos arquivos (mais `vendor/sat_sav_parse`, o parser de saves) num zip carregado pelo Pyodide dentro de um Web Worker.\n- `web/` é o frontend (Vite + TypeScript vanilla, sem framework), publicado no GitHub Pages.\n- O parser binário de saves é o [sat_sav_parse](vendor/sat_sav_parse/) (vendorizado; veja a licença própria em `vendor/sat_sav_parse/LICENSE`).\n- `assets/map_1.0.jpg` é o mapa do jogo usado como camada base; a calibração mundo→mapa vive em `src/report.py` e `web/src/map/calibration.ts`.\n\n## Ideias futuras (contribuições bem-vindas)\n\n- **Facing dos sinais existentes**: ler a rotação dos sinais que o jogador já colocou — sinal só num sentido = mão única naquele sentido; nos dois = bidirecional confirmado pelo próprio jogador. Também consertaria a limitação atual de \"sinal do mesmo tipo virado para o lado errado conta como já existente\".\n- **Balloon loops**: detectar laços de retorno pendurados por um único nó (laço mão única + haste bidirecional).\n- Aplicar a geometria da agulha também no modo mão única puro (hoje ela é exclusiva do misto para manter o modo antigo intacto).\n\n## Contribuindo\n\nTeve uma ideia boa ou achou um bug? **Contribuições são bem-vindas** — abra uma [issue](https://github.com/dvduardo/sinaleiro/issues) para discutir ou mande direto uma [pull request](https://github.com/dvduardo/sinaleiro/pulls) (a `main` é protegida; toda mudança entra por PR).\n\nPara uma PR tranquila:\n\n1. Faça o fork e rode o projeto localmente (seção acima).\n2. `cd web \u0026\u0026 npm run build` precisa passar — é o mesmo check que o CI roda na sua PR.\n3. Se mexer no pipeline Python (`src/`), rode também `npm run smoke` com um save seu: ele garante que o resultado no navegador (Pyodide) continua idêntico ao do CPython.\n4. Conte na descrição o que muda para o jogador — de preferência com um print do mapa.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdvduardo%2Fsinaleiro","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdvduardo%2Fsinaleiro","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdvduardo%2Fsinaleiro/lists"}