Advanced

MyJourney: crie demos de produtos sem desperdiçar um dia inteiro

My journey cover
On this page

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 fluxo do myjourney: de URL e descrição para um MP4 na galeria, passando por planejador, plano JSON, aprovação humana, gravação, narração e montagem, e portões de qualidade.

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.

App architecture: a web server writes jobs to a single database and the page follows along over SSE; a worker picks up jobs with a lease and writes progress back.

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:

—
establishMission Control, a visão diária do trabalho aberto
surveyo que cada projeto relata ali
traversea segunda área do produto, que abre filtrada para você
demonstratealtera o filtro para "All"
revealo trabalho de toda a conta aparece de uma vez
traverseuma terceira área do produto
closefecha 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.

A frame from the tour: Mother's Mission Control in dark theme. The cursor drawn by myjourney, an arrow with an orange ring around it, rests over the link for the geeksilva97/myjourney project. The card shows PR number 1, "The app: a queue, a worker, and a route you can edit", gate Clear, reviewed by Edy Silva 19 hours earlier, and the four capabilities underneath: gate, review, assessment and context. In the bottom-left corner, inside a circle, the video's presenter speaks the narration.

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 demonstrate seguido por um reveal. 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.

Um frame do tour: Mother's Work Feed com a aba All ativa. O anel do cursor destaca uma linha na lista, que mostra gates de vários projetos, myjourney PR 1 "The app: a queue, a worker, and a route you can edit" com 8 tópicos e Done, mother PR 108 "Review-request guardrails + Mission Control capability redesign", myjourney42 PR 24 "fix: serialize renders + retry flaky narration (prod CPU/RAM saturation)". No rodapé, a sobreposição que o tour escreveu: "Every gate, every agent, one feed". No canto inferior esquerdo, o apresentador.

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:

—
PlanningClaude Opus, com ferramentas de navegadorAPItokens de exploração
Voz em inglêsKokorolocal$0
Voz em portuguêsminimax-speech-02-hdRunPod$0.0276
Retrato do apresentadorFLUX.1-devRunPod$0.012
Lip-sync do apresentadorInfiniteTalkRunPod$0.25
Gravação e montagemPlaywright, CDP e ffmpeglocal$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.

Um frame do tour do Codeminer42: a seção de serviços do site com o cursor desenhado sobre o texto, uma sobreposição com a frase "Onboarding support and flexible staffing" no rodapé do card e, no canto inferior esquerdo, dentro de um círculo, o apresentador gerado falando a narração.

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!

We want to work with you

The engineers who write here are the same ones who join client teams. Let’s build something that grows with your business.

Book a call