Compilar a partir do Código-fonte
Electron 43, React 19, TypeScript 7, Vite 7, Tailwind 4.
git clone https://github.com/samaBR85/Valendo-TeleprompterSuite.git
cd Valendo-TeleprompterSuite
npm install
npm run dev
Se o npm install não baixar o binário do Electron, execute node node_modules/electron/install.js.
No Windows, o Abrir Valendo.bat faz a instalação e o build no primeiro duplo clique, para quem não tem um terminal aberto.
Comandos
| Comando | O que faz |
|---|---|
npm run dev | Desenvolvimento, com hot reload |
npm run build | Empacota o main, o preload e o renderer em out/ |
npm test | A suite de testes |
npm run typecheck | tsc --noEmit |
npm run start:debug | Roda o app compilado com depuração remota na porta 9222 |
npm run verify | Verifica os critérios de aceitação contra o app em execução (precisa do start:debug) |
npm run dist:win | O instalador do Windows (NSIS) em dist/ |
npm run dist:mac | As imagens de disco do macOS, arm64 e x64, em dist/ |
dist:mac só funciona no macOS — as ferramentas de assinatura da Apple não existem em outros sistemas. O fluxo de release compila cada plataforma em seu próprio runner.
Macs Intel
Não há download para Intel. O app compila e roda perfeitamente em macOS Intel — npm run dist:mac -- --x64 produz a imagem de disco — mas o build não é publicado, porque os runners Intel do macOS no GitHub nunca estiveram disponíveis: o job ficou na fila por três tentativas consecutivas sem nunca começar. Um instalador que não pode ser produzido de forma confiável é uma promessa, não uma release.
Reabrir isso é uma mudança de duas linhas na matriz do workflow, e o script de build do ffmpeg já é agnóstico quanto à arquitetura — compila para qualquer máquina em que roda.
Releases
.github/workflows/release.yml compila Windows e macOS arm64 sempre que uma tag v* é empurrada, e anexa os instaladores à release. Os runners macos-14 são Apple Silicon, que é onde a imagem de disco arm64 precisa ser compilada.
Rodar o workflow manualmente (Actions → Release → Run workflow) compila os mesmos artefatos sem criar uma release, e os deixa como artefatos de job baixáveis — útil para testar um build antes de decidir que vale uma tag.
O build dist:mac é assinado ad-hoc: o Apple Silicon se recusa a abrir um binário sem assinatura nenhuma, mas a assinatura ad-hoc não diz nada sobre quem o construiu. Um build que você mesmo faz roda sem drama, porque nada foi baixado para ser posto em quarentena. O .dmg da página de download é um build à parte, assinado com um Developer ID e notarizado pela Apple, então abre com dois cliques também.
Layout
src/main/ janelas, monitores, estado autoritativo, persistência
src/preload/ a ponte IPC exposta ao renderer
src/shared/ lógica pura e testável: âncora, linhas, velocidade, histórico, comandos
src/renderer/ prompter (compartilhado), interface do operador, janela de transmissão
scripts/ verificação end-to-end pelo protocolo Chromium
docs/ capturas de tela usadas no README e neste manual
A forma da coisa
Há um estado autoritativo, no processo principal, em src/main/state.ts. Os renderers nunca guardam sua própria cópia de qualquer coisa que importe; eles despacham ações e espelham o que volta.
src/shared não tem Electron nem React. É onde ficam a âncora, a composição de linhas, a aritmética de velocidade, o histórico de desfazer e o registro de comandos, e é onde estão quase todos os testes — a lógica pode ser provada sem lançar uma janela.
Testes
npm test
A suite cobre a lógica pura e as partes do processo principal que podem ser alcançadas com uma pasta userData mockada: a âncora após um refluxo, composição de linhas, velocidade nos três modos, o que viaja e o que não viaja dentro de um .valendo, migração de projetos escritos por versões mais antigas e os dicionários de i18n.
O teste de i18n vale conhecer: ele garante que todos os seis dicionários têm exatamente o mesmo conjunto de chaves, que nenhum está vazio e que as marcas {interpolation} sobrevivem à tradução. Esquecer um idioma quebra o build em vez de enviar um rótulo em branco.
Verificações end-to-end
scripts/verify.mjs conduz o app em execução pelo Chromium DevTools Protocol: lança com uma pasta de dados de usuário isolada, despacha entrada real e faz asserções contra o DOM real. É assim que os critérios de aceitação são verificados — incluindo o que importa mais, que a palavra sob a linha de leitura não se move quando o texto acima dela muda.
npm run start:debug # em um terminal
npm run verify # em outro
Versionamento
A versão semântica é uma decisão humana, definida à mão em package.json. O número de build sobe sozinho a cada npm run build, através de scripts/bump-build.mjs, e aparece no cabeçalho do app e nos créditos como vX.Y.Z - build N.
Portanto, um relatório de bug que nomeia um vX.Y.Z - build N exato aponta para um pacote preciso, sem que ninguém precise se lembrar de incrementar um número antes de cortar uma release.
ffmpeg redistribuído
Os dois instaladores carregam binários diferentes, sob licenças diferentes.
Windows. ffmpeg 6.1.1 do gyan.dev, fixado em package-lock.json e baixado através do ffmpeg-static. GPL 3.0, configurado com --enable-gpl --enable-version3 --enable-libx264.
macOS. ffmpeg 6.1.1 compilado a partir do código-fonte pela própria CI deste projeto, a cada release, através de scripts/build-ffmpeg-mac.sh. Remove o libx264 e codifica pelo VideoToolbox do próprio sistema, o que mantém o resultado LGPL 2.1 — a Mac App Store não aceita software GPL. O próprio guard do script falha o build se --enable-gpl, --enable-version3 ou --enable-nonfree aparecerem no resultado, ou se o binário não se reportar como LGPL 2.1.
Execute-o diretamente para reproduzir o binário do macOS:
scripts/build-ffmpeg-mac.sh
Não recebe argumentos além de um FFMPEG_VERSION opcional (padrão 6.1.1), e imprime a string configuration: resultante e o aviso de licença no final.
De qualquer forma, a fonte correspondente para ambas as plataformas é o release oficial do FFmpeg 6.1.1, sem modificações: ffmpeg.org/download.html e o repositório oficial, tag n6.1.1. Detalhamento completo de licenças: ffmpeg redistribuído.
Como o ffmpeg é um executável real, é desempacotado ao lado do app.asar em vez de dentro dele — um binário arquivado não pode ser executado.
Contribuição
Issues e pull requests são bem-vindos. Duas coisas a saber antes de abrir um:
- Os comentários nesta base de código explicam o porquê, não o quê. Um comentário que reafirma a linha abaixo será solicitado a dizer outra coisa.
- Se uma mudança tocar a posição de leitura, ela precisa de um teste. Essa é a única promessa sobre a qual todo o app é construído.