
MyJourney: crie demos de produtos sem desperdiçar um dia inteiro
Table of Contents
GemLab tem vários projetos rodando ao mesmo tempo, e todos eles mudam de semana para semana. Então alguém pergunta como a "Mãe" está, e a resposta honesta é compartilhar a tela e navegar por ela juntos.
Gravar uma demo real resolve isso uma vez. Roteiro, gravação, um erro no meio, regravar, cortar, fazer o upload. Um dia inteiro de trabalho de alguém. E no próximo deploy, a tela mudou e a demo está desatualizada.
Multiplique isso por vários projetos e você entenderá por que ninguém regrava.
É por isso que o myjourney existe: você fornece uma URL e uma descrição do que deseja mostrar, e ele entrega um MP4 narrado. Ele opera um navegador real pelo site, com um cursor visível, e narra o que está fazendo.
Ainda está em um estágio muito inicial, então espere imperfeições. Mas o fluxo de ponta a ponta já funciona.
O que ele faz
Você preenche um formulário: a URL, a descrição e, opcionalmente, um logotipo e uma capa. Alguns minutos depois, há um vídeo na galeria. O caminho entre um e outro é este:

O planejador explora o site em um navegador real, da mesma forma que um visitante explora: ele navega, lê e testa as coisas antes de prometer uma cena sobre elas. Quando um plano cria um trecho em torno da busca do site, é porque ele digitou naquela busca primeiro e observou a resposta do preenchimento automático. Ao final, ele escreve o plano: os beats do tour, em JSON.
O plano para e aguarda que alguém o aprove. O planejamento é rápido e barato; a gravação mantém um navegador e uma codificação ffmpeg por vários minutos. Portanto, a rota é escrita primeiro e fica na fila até que alguém diga que vale a pena gravá-la.
Uma vez aprovado, um worker assume o controle. O plano é compilado em um script Playwright, que controla o navegador. A gravação vem do screencast do CDP, o protocolo DevTools do Chromium, que emite um quadro a cada pintura de página. E o cursor que você vê no vídeo não existe para o sistema: a entrada sintética não tem ponteiro, então o cursor é um elemento DOM que injetamos e animamos. No final, a narração se torna voz e o ffmpeg monta o corte com trilha sonora e marca d’água.
Nos bastidores, o app é deliberadamente pequeno: dois processos e um banco de dados em um único arquivo. Sem broker, sem fila externa, a fila é uma tabela, um evento é uma linha.

O servidor escreve uma linha no banco de dados e responde. O worker pega o trabalho com um lease e continua escrevendo o progresso. A página do cliente acompanha através de um fluxo de eventos que lê esses mesmos eventos do banco de dados. Qualquer um dos processos pode morrer e retornar sem que o outro perceba.
A gravação em si roda sobre o argo, que transforma um script Playwright e um manifesto de cena em um vídeo narrado. O myjourney fornece a parte que o argo assume que um humano escreveu: olhar para um site que nunca viu e decidir como deve ser um tour por ele.
Um exemplo público, que também abre a página inicial de myjourney42.cm42.io: o tour pelo site do Codeminer42. Ninguém escreveu um roteiro, desenhou um storyboard ou abriu um editor:
Assista ao final do vídeo: ele realmente preenche o formulário de contato. Ninguém pediu para ele fazer isso; o formulário estava lá, e era o próximo passo natural para quem estivesse assistindo.
Onde o modelo não decide
Esse formulário de contato preenchido sem que ninguém pedisse é encantador em um site público. Agora imagine o mesmo entusiasmo aplicado a um botão de excluir.
É por isso que o beat que clica declara seu próprio risco, e a validação re-deriva esse risco por conta própria, e se recusa a clicar em qualquer coisa que corresponda a excluir, comprar, finalizar compra, cancelar assinatura, convidar ou sair, não importa o que o plano tenha declarado. Passar o mouse sobre um botão de excluir para mostrar que ele existe é aceitável. Pressioná-lo não é.
O modelo não se autocertifica. Nunca.
E então há a outra fronteira: a maioria dos produtos que valem uma demonstração vive atrás de um login. O site de marketing é aberto, mas a coisa que está sendo vendida está atrás de um formulário. Um tour que vê apenas o que um estranho vê é um tour da metade errada.
Fazer o login é trabalho de uma pessoa. npm run login abre um navegador real, você faz o login conforme o aplicativo solicita, senha, SSO, 2FA, link mágico, chave de hardware, e pressiona Enter. Tudo funciona, porque quem está fazendo isso é um humano e não um script tentando adivinhar seletores. Nenhuma senha é digitada, armazenada ou vista por um modelo.
O que ele descobriu por conta própria
É por isso que a primeira demonstração que gravamos de verdade foi de um app com login: Mother, um projeto nosso que fica entre o seu agente de IA e a sua branch principal. É o tipo de produto que é difícil de explicar em texto e fácil de entender assistindo.
O plano que o myjourney escreveu para o Mother tem sete beats e 58 segundos. O arco funciona assim:
| — | ||||
|---|---|---|---|---|
establish | Mission Control, a visão diária do trabalho aberto | |||
survey | o que cada projeto relata ali | |||
traverse | a segunda área do produto, que abre filtrada para você | |||
demonstrate | altera o filtro para "All" | |||
reveal | o trabalho de toda a conta aparece de uma vez | |||
traverse | uma terceira área do produto | |||
close | fecha voltando ao Mission Control |
Olhe para esse último beat. A narração que ele escreveu foi: "O loop se fecha no Mission Control, onde o próximo portão aparece assim que seu agente abre um pull request."
Ele encontrou o loop do produto e o tornou o loop do tour. Ninguém pediu isso. O que demos a ele foi uma URL, uma descrição e uma sessão logada.

Olhe para o card onde o cursor está apontando: é o myjourney, com seu PR número 1. Mother está governando o myjourney enquanto o myjourney grava a demo da Mother.
O modelo escreve JSON, nunca código
O modelo encontrou o loop do produto por conta própria. Você poderia concluir que, a partir daí, basta confiar nele. Mas há uma coisa que ele nunca escreve neste pipeline: código.
A abordagem óbvia seria pedir o script do Playwright diretamente ao modelo. Ele escreve JavaScript bem, o Playwright é bem documentado e funciona de primeira.
Na décima vez, ele te entrega um arquivo com erro de sintaxe. Ou pior: um arquivo que executa e faz algo que você não pediu.
É por isso que o modelo aqui não escreve código. Ele escreve JSON, e um compilador que escrevemos transforma isso em Playwright. O arquivo gerado é apenas uma camada fina em torno de um literal:
const PLAN: TourPlan = { /* ... */ };
test('tour', async ({ page, narration }) => {
await runTour(page, narration, PLAN);
});Todo o comportamento reside em tour-runtime.ts, que é escrito e testado à mão. Um plano ruim é um erro de validação, nunca um erro de sintaxe em um arquivo que alguém tem que debugar às 3 da manhã.
E há a melhor parte, que é o que o modelo não consegue dizer. Um gotosó consegue alcançar um caminho na própria origem do tour. Uma chave só pode ser uma de um conjunto fechado. A DSL não tem como expressar "abrir outra aba e fazer login em outro lugar", porque não existe um verbo para isso.
É como um pedido de restaurante. O garçom anota o pedido; a cozinha decide como cozinha. E o garçom não pode escrever um prato que a cozinha não faz.
O custo disso é a expressividade. Uma nova capacidade não é um ajuste no prompt, é uma mudança no compilador e em seus testes. Quando o domínio é genuinamente aberto, deixar o modelo escrever código vence. Aqui, o domínio é fechado de propósito, então a DSL vence por uma margem ampla.
Funcionou no primeiro dia, e o vídeo era inútil
Com o compilador detendo a sintaxe, o pipeline de renderização ficou de pé no primeiro dia. E os primeiros vídeos eram voz sobre um print, não como impressão, mas como medição: de 46 a 54% de cada vídeo era um quadro estático. Uma abertura tinha oito segundos de uma página inicial imóvel com uma voz falando por cima.
A causa não era um bug. Era estrutural.
A narração definia a duração do beat. Cada ação levava o tempo que levasse. E a sobra se tornava um hold no final. Nada era esticado, então o tempo vago se tornava uma foto por padrão.
É por isso que cada beat hoje declara um shot, o que ele existe para fazer, e tem uma ação elástica que cresce para preencher qualquer narração restante. drift rola a página continuamente, sweep envia o ponteiro visitando vários alvos, dividindo o tempo entre eles, push é movimento de câmera no ffmpeg e funciona até em uma página que não anima nada.
hold ainda existe, limitado a 800ms, porque hold era o problema.
O resultado: o vídeo se move quase o tempo todo, e é isso que faz com que pareça um tour que alguém gravou em vez de um slideshow narrado.
A alocação é decidida ao vivo, não pré-computada, porque não há como saber quanto custa um clique antes de clicar. Se uma navegação demora, as ações seguintes encolhem em vez de ultrapassarem a narração.
Um trabalho pode terminar com sucesso e não valer nada
O vídeo começou a se mover. Mas o pipeline continuou relatando sucesso em vídeos que não eram bons. Por isso, quatro portões de qualidade antes da publicação, e cada um nasceu de um vídeo que passou por tudo e não era utilizável:
- shape: a validação do compilador, aquela que nunca se torna um erro de sintaxe;
- composition: estruturalmente é uma demonstração. Começa estabelecendo, fecha com um próximo passo, e tem pelo menos um
demonstrateseguido por umreveal. Sem esse par, você tem uma galeria de capturas de tela narrada, que foi exatamente o que as três primeiras amostras foram; - motion: pelo menos 70% da gravação tem algo se movendo, medido por beat do vídeo;
- pixels: detecção de quadro em branco para um site que não renderizou, e assinaturas de texto para desafios de bot.
O quarto portão tem a melhor história. google.com passou tranquilamente pelo teste de quadro em branco enquanto exibia um reCAPTCHA, porque uma página de CAPTCHA é cheia de conteúdo. Foi necessário um portão que lê o que está escrito, não o quanto está pintado.
E os portões têm um limite, o que descobri revisando um dos tours pela quinta vez. Um beat cai em uma tela que ainda não tem dados, um estado vazio, com a narração prometendo a funcionalidade sobre ela. motion passou, porque o ponteiro se move e a câmera avança. composition passou, porque o arco está correto. Nenhum dos dois consegue dizer se a tela tinha algo para mostrar.
Um portão mede o que pode ser medido. "Esta tela vale a pena ser mostrada" ainda é um julgamento humano.

Os modelos e serviços no pipeline
Se o julgamento final é humano, todo o resto no pipeline é máquina. E uma máquina tem um nome e um preço na etiqueta:
| — | ||||||||
|---|---|---|---|---|---|---|---|---|
| Planning | Claude Opus, com ferramentas de navegador | API | tokens de exploração | |||||
| Voz em inglês | Kokoro | local | $0 | |||||
| Voz em português | minimax-speech-02-hd | RunPod | $0.0276 | |||||
| Retrato do apresentador | FLUX.1-dev | RunPod | $0.012 | |||||
| Lip-sync do apresentador | InfiniteTalk | RunPod | $0.25 | |||||
| Gravação e montagem | Playwright, CDP e ffmpeg | local | $0 |
Um tour completo, com um apresentador falando, custa cerca de trinta centavos mais os tokens de planejamento.
O planejamento é o único lugar onde um modelo grande entra: um Claude Opus com ferramentas de navegador. Em um dos primeiros tours, foram necessárias 18 chamadas de ferramentas de exploração para sete beats que passaram na validação na primeira tentativa.
A voz em inglês é Kokoro, um TTS aberto que roda localmente, sem chave de API. A voz em português foi mais divertida: o Kokoro fornece os pesos para uma voz brasileira, mas o pacote JavaScript bloqueia em três camadas antes de chegar a eles, sendo a última o fonemizador, que só fala inglês. Portanto, o português é narrado por minimax-speech-02-hd, em um endpoint do RunPod, pelos centavos que a tabela mostra.
Um efeito colateral interessante: um tour em outro idioma não é uma tradução. O plano é refeito do zero no idioma de destino, e surge um tour diferente; o planejador de português encontrou um caminho pelo site que o tour em inglês nunca tocou.
O apresentador no canto são dois modelos. O retrato vem do FLUX.1-dev; a sincronia labial é o InfiniteTalk, aberto (Apache 2.0), em um endpoint público do RunPod, $0,25 por renderização em 480p, independentemente da duração. Ele é guiado pelo áudio da narração, não pelo texto: a boca para de se mover exatamente quando a voz para, porque nesse ponto o áudio é silêncio. E porque é guiado por áudio, é agnóstico ao idioma por construção; o tour em português não precisou de nenhuma linha alterada nesta etapa.

E o pipeline aceita seu próprio material. Não quer um rosto gerado? Faça o upload de um retrato seu, e será essa pessoa quem fará a narração; a sincronia labial custa os mesmos US$ 0,25. O branding também entra: uma capa de abertura, um logotipo no canto como marca d’água e música de fundo sob a narração. Tudo isso entra junto com a URL, e o ffmpeg grava isso no corte final.
Nada disso foi a primeira opção que surgiu. Houve primeiro uma pesquisa, o que existia em modelos abertos e comerciais, e experimentos mensurados depois. A família que repinta bocas, Wav2Lip, MuseTalk, LatentSync, estava fora porque ela dubla vídeos existentes, e tudo o que temos é um retrato estático. O WAN 2.6 foi comparado lado a lado e perdeu porque não cala a boca: durante as pausas da narração, ele continua mastigando o ar, com 0,56 de movimento no silêncio contra 0,28 do InfiniteTalk. Esses experimentos se tornaram cadernos de laboratório no repo, com custos e medições anotados.
Essa pesquisa foi feita da maneira que trabalhamos no laboratório: com o Claude. O Claude Code realizou a pesquisa de modelos, escreveu os relatórios que serviram de base para a escolha e executou os experimentos que produziram os números acima. Já escrevi sobre como o uso no dia a dia em Claude Code: a eficácia irracional da simplicidade.
A demo se tornou um artefato de build
Lá no início, a pergunta era "como está a Mother?". Hoje a resposta é um MP4 de um minuto que custou cerca de trinta centavos, e que pode ser regravado amanhã, quando a tela mudar.
É isso que muda o cenário. Quando uma demo custa o dia de alguém, ela é um evento: nós a adiamos, ela envelhece, e volta o "deixe-me compartilhar minha tela". Quando custa centavos e não consome as horas de ninguém, ela se torna um artefato de build: a interface mudou, regrave, exatamente como rodar a suíte de testes após um commit.
E é nisso que estamos trabalhando agora: otimizando o pipeline para que a regravação e a troca de partes do vídeo, uma cena, uma narração, uma marca, fiquem cada vez mais baratas, sem pagar por todo o caminho novamente. E tours mais longos também, porque agora o teto é de um minuto. É o antigo conselho de Kent Beck: faça funcionar, faça do jeito certo, faça rápido. Fazer funcionar foi o primeiro passo; estamos no meio da lista.
O myjourney está no ar em myjourney42.cm42.io, naquela fase inicial da qual eu avisei. O GemLab resume a tese em uma frase melhor que a minha: construir um MVP tornou-se trivial; ter um software real ainda é difícil.
Por hoje é tudo.
We want to work with you. Check out our Services page!



