Communitygithub.com

msertdev/keepwatching

Um banco de dados de retenção para formatos de vídeo curtos (9:16). Renderiza, nomeia formatos, armazena prévias compromissadas, medições reais e tamanhos de amostra visíveis. Node + Playwright + ffmpeg, instalável como skill de agente.

O que é keepwatching?

Keepwatching é um banco de dados de formatos de vídeo curtos (9:16) que renderiza e rastreia métricas reais de retenção. Cada formato é composto por três arquivos: uma especificação de renderização, uma hipótese declarada e os dados de medição (ou nenhum, se não testado). A regra fundamental é nunca inventar uma taxa de retenção: toda alegação deve vir de `formats/<slug>/data.yml`, com um `n` amostral visível (0 significa não testado). A skill é útil para criadores de conteúdo que desejam basear decisões de formato em evidências, não em suposições. Ela suporta renderização via Node + Playwright + ffmpeg, permite criar novos formatos a partir de templates, executar testes A/B, e ingerir dados de analytics (YouTube Studio, TikTok) para gerar relatórios. A skill também impõe determinismo (mesmo `format.json` gera os mesmos quadros para sempre) e regras rígidas de honestidade (nunca escrever `data.yml` manualmente, nunca misturar medições de formato e de eixo de conteúdo).

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add msertdev/keepwatching

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

O que keepwatching faz?

Um banco de dados de formatos de vídeo curtos que renderiza. Cada formato é composto por três arquivos: uma especificação de renderização, uma hipótese declarada e o que as medições dizem — incluindo "nada ainda".

A regra que torna esta skill útil: nunca invente um número de retenção. Toda alegação sobre o desempenho de um formato vem de formats/<slug>/data.yml, e cada uma delas carrega um n. Se n: 0, a resposta honesta é "não testado" — e deve ser dito.

Configuração — faça isso primeiro, em toda sessão

Esta skill aciona um renderizador real que reside no repositório keepwatching. As instruções sozinhas não podem renderizar nada, então o primeiro passo é sempre localizar ou instalar o repositório.

# 1. Encontre-o. O primeiro match vence; pergunte ao usuário se nenhum destes existir.
KW="${KEEPWATCHING_HOME:-}"
[ -z "$KW" ] && [ -d ./keepwatching ] && KW="$PWD/keepwatching"
[ -z "$KW" ] && [ -d "$HOME/keepwatching" ] && KW="$HOME/keepwatching"
[ -z "$KW" ] && { git clone https://github.com/msertdev/keepwatching "$HOME/keepwatching" && KW="$HOME/keepwatching"; }
cd "$KW"

# 2. Instalação única. Seguro para re-executar; não faz nada se já foi feito.
npm install && npm run setup

# 3. Confirme que a biblioteca está intacta antes de fazer qualquer outra coisa.
npx kw check

As 24 prévias da galeria estão compromissadas, então npx kw gallery mostra a página em segundos sem renderizar nada. npm run setup só é necessário para renderizar vídeo. Se você alterar a scene de um formato, a prévia compromissada fica desatualizada — re-renderize e comprometa-a com npx kw gallery --no-serve && git add site/previews, ou o CI do kw previews check falhará.

kw check imprimindo no problems significa que você está pronto. Se ele reportar fontes faltando, execute npm run setup novamente — a composição se recusa a renderizar com uma fonte substituta, pois uma fonte substituída alteraria silenciosamente cada quadro que o repositório já mediu.

Duas notas práticas.

  • Variáveis de shell não persistem entre chamadas de ferramenta na maioria dos harnesses de agente. Recalcule KW em cada comando ou inicie cada um com um cd /caminho/absoluto/para/keepwatching && explícito. Não presuma que $KW sobrevive.
  • npm run setup pode levar minutos em uma máquina fria. Ele baixa Inter (≈30 MB) e um Chromium headless (≈150 MB). Em uma máquina que já tem ambos em cache, termina em segundos. Informe ao usuário qual está acontecendo, em vez de parecer que travou.

Todo comando neste arquivo presume que a raiz do repositório é o diretório de trabalho. Se o usuário estiver trabalhando em um projeto diferente, renderize dentro do repositório e copie o MP4 de volta; kw não funciona de fora dele.

Existe também npm run check, que é kw check mais tsc --noEmit. Use esse se você editou algo em engine/.

As quatro coisas que você será solicitado a fazer

1. Escolher um formato para um tópico

npx kw list          # todo formato, com seu tamanho de amostra e retenção medida

Leia formats/<slug>/meta.yml para a hypothesis, useWhen e avoidWhen. Corresponda a forma do conteúdo à família de formato, não ao tópico.

Todo formato na tabela abaixo está atualmente com n = 0. Estes são pontos de partida escolhidos com base em uma hipótese declarada, não vencedores escolhidos com base em evidências. Diga isso quando recomendar um. A tabela informa qual formato afirma ser adequado a uma forma de conteúdo; ela não informa qual tem melhor desempenho.

O conteúdo é…FamíliaComece com
um grande númerostat-counterstat-counter-rise
uma recompensa que vale a esperacountdowncountdown-clock
um conjunto ordenado de itensrankingranking-suspense (conclusão) ou ranking-reveal (compartilhamentos)
duas opções que diferem em um númerocomparisonsplit-compare
o mesmo sujeito em dois estadosrevealbefore-after
uma crença falsa generalizadamyth-factmyth-vs-fact
uma frase fortecold-opencold-open-line
um processo com estágios reaisprogressprogress-bar
valores que realmente escalamescalationescalation-ladder
algo circularreverseloop-seam

Ao recomendar um, cite seu n. "ranking-suspense, embora não testado neste repositório (n=0)" é uma boa recomendação. "ranking-suspense obtém 68% de retenção" é uma fabricação, a menos que data.yml diga isso.

2. Renderizar um vídeo

Copie um formato, preencha o bloco data, renderize:

npx kw new my-clip --from=stat-counter-rise
# edite formats/my-clip/format.json -> "data": { ... }
npx kw render my-clip           # -> out/my-clip/master.mp4

# Opcional: veja em um navegador primeiro, sem codificar nada.
# Bloqueia até você pará-lo, então pule ao executar sem supervisão.
npx kw preview my-clip

Edite apenas data a menos que o layout realmente precise mudar. O array scene é o formato; alterá-lo faz do clipe um formato diferente, e suas medições não se transferem mais. Se você alterar a cena, aumente version em format.json — o id da variante deriva dela.

Alterar a duração — leia isto, é o pedido mais comum.

Os formatos da biblioteca duram 8–30 segundos (21 de 24 entre 8 e 14). Os três de 30 segundos — cold-open-question, countdown-clock, stat-counter-rise — são os níveis de um experimento em andamento, não a duração padrão. Qualquer duração que um formato ainda não tenha requer editar a cena, então "editar apenas data" não se aplica. Use esta regra:

Multiplique canvas.durationSec e cada tempo na cena por novaDuracao / antigaDuracao. Depois observe a cauda: a escala estica a espera final pelo mesmo fator, então quanto maior o fator, pior fica o final.

Exemplo prático — stat-counter-rise de 10s para 30s, fator 3,0. Estes são os números que realmente foram enviados, não uma ilustração:

campo10s×3enviado
canvas.durationSec103030
counter endSec6,419,221,0
bar endSec6,419,221,0
unit at6,419,221,0
context at / in.at6,519,521,6
source at——25,5 — um batida que não existia
posterSec8,425,227,5

A escala sozinha deixou a última batida em 19,5s em um clipe de 30 segundos: 10,5 segundos de um quadro congelado. Empurrá-lo para 21,6 também não foi suficiente. Acima de um fator de aproximadamente dois, a aritmética para de ser a resposta — o clipe precisa de uma batida que não tinha. Aqui, uma linha de citação em 25,5s, que o formato estava reivindicando em seus sources o tempo todo e nunca havia colocado na tela. Espera final: 4 segundos.

Um card final mantido por mais de cerca de 3 segundos é silêncio morto, e silêncio morto no final é o que mata a taxa de conclusão. kw frame0 falha completamente em 5 segundos de uma tela imóvel: 3 é o conselho técnico, 5 é o piso duro. Ele encontrou três formatos que já haviam sido enviados com um final congelado de 6 segundos.

Restrições e verificações:

  • durationSec × fps deve ser um número inteiro de quadros.
  • Aumente version em format.json sempre que alterar a cena — reajuste de tempo conta. Um esqueleto novo em 0.1.0 que você depois reajusta se torna 0.2.0. O id da variante deriva de version mais um hash da especificação, então isso mantém uma medição futura atribuível.
  • npx kw check captura tempos além do final do clipe, e npx kw frame0 captura um primeiro quadro que não pinta nada, além de qualquer trecho imóvel com mais de 5 segundos. Nenhum deles pode dizer que um clipe é chato — para isso, abra out/<slug>/contact.png após a renderização. Ele amostra seis quadros uniformemente pelo clipe, então tiles quase idênticos são visíveis de relance.

Fontes. kw new --from=<slug> redefine deliberadamente o esqueleto para sampleContent: placeholder e descarta os sources do formato pai — as citações do pai respaldavam os números do pai, não os seus. Se você colocar um número real na tela, defina sampleContent: sourced e adicione uma entrada em sources: com uma URL e a alegação exata que ela respalda.

Um número com fonte só é considerado com fonte quando aparece. Se você animar um contador para um valor citado, marque-o como claim: "final" e mantenha a unidade e qualquer palavra como "exatamente" fora da tela até endSec — mostre "contando…" até lá. Todos os outros elementos visíveis durante a contagem precisam de neutralWhileCounting: true. kw check recusa o formato caso contrário. Contadores cujos valores intermediários são honestamente verdadeiros ("quadros até agora") são marcados como claim: "running" e estão isentos.

O que conta como fonte: algo que um leitor possa abrir e verificar o número — um artigo primário ou seu registro permanente (DOI, PubMed), um órgão normativo, uma agência estatística, um relatório oficial. Não uma listicle, não um blog resumindo uma, e não sua própria lembrança. Declare qualquer arredondamento que você fez para a tela no campo claim. kw check verifica se uma URL e uma alegação estão presentes; não pode verificar se são verdadeiras, então essa parte é com você. Se não conseguir encontrar uma fonte, use texto de preenchimento — uma estatística inventada é a mesma falha que um número de retenção inventado.

Veja references/spec.md para a referência completa do format.json.

3. Executar um teste A/B

Dois formatos, mesmo conteúdo, mesmo dia:

npx kw new test-a --from=cold-open-line
npx kw new test-b --from=redacted-reveal
# coloque cópia idêntica em ambos os blocos de dados
npx kw render test-a && npx kw render test-b
npx kw variant test-a           # registre esta string contra o upload

O variantId em out/<slug>/variant.json é o que torna o resultado atribuível. Registre-o contra o vídeo publicado no momento do upload — ele também é escrito no comentário de metadados do MP4 se você perder suas anotações.

4. Ler as medições de volta

# exporte CSVs do YouTube Studio / TikTok analytics para measure/inbox/
npx kw measure                  # ingira + reporte -> measure/report.md
npx kw measure apply            # escreva resultados em formats/*/data.yml
npx kw gallery                  # re-renderize + reconstrua a galeria

Sem API, sem OAuth. Veja references/measuring.md para as etapas exatas de exportação e o formato mapping.csv.

Determinismo é o contrato

O mesmo format.json produz os mesmos quadros, em qualquer máquina, para sempre. É isso que permite que uma curva de retenção seja atribuída a um formato, não a uma renderização. Ao editar o motor, nunca introduza Date.now(), Math.random(), requestAnimationFrame, transições CSS, ou animações CSS na composição. npx kw render <slug> --check-determinism reposiciona quadros fora de ordem e falha se qualquer pixel se moveu.

Duas medições que nunca devem ser misturadas

data.yml tem dois blocos, e eles respondem a perguntas diferentes:

BlocoPerguntaClassifica a biblioteca?
formatComo esta estrutura de cena se comporta?Sim
content_axisComo este assunto se comporta?Não

Um único vídeo publicado carrega ambos os rótulos — é uma contagem regressiva e é sobre o corpo. Fazer a média dos dois produz um número que não responde a nenhuma das perguntas, então eles são armazenados separadamente, reportados separadamente e mostrados em cores diferentes na galeria.

Ao reportar um resultado, diga qual é:

  • "countdown-clock reteve 62% (n=6)" — uma alegação de formato.
  • "assuntos pessoais/do corpo retiveram 68% (n=9)" — uma alegação de eixo.
  • "contagens regressivas pessoais/do corpo retiveram 68%" — nenhuma das duas, a menos que você também diga quantos vídeos, em quais formatos, e que os dois estão confundidos.

measure/report.md imprime uma coluna carregado por para cada eixo. Se um eixo foi carregado por apenas um formato, esse resultado de eixo e esse resultado de formato são os mesmos vídeos usando dois rótulos; diga isso em vez de apresentá-los como duas descobertas independentes.

Os eixos de conteúdo são declarados em data/content-axes.yml e anexados a um vídeo pela coluna opcional content_axis em measure/mapping.csv. Eles são os eixos do próprio usuário, não os da biblioteca — adicione qualquer distinção que ele realmente testar.

variant_id: not-in-library marca um vídeo publicado cujo formato não está neste repositório. É apenas uma amostra de eixo de conteúdo: nunca chega ao painel de formatos ou a qualquer data.yml, e carregado por o nomeia para que a lacuna seja visível. Resultados de eixo a nível de repositório ficam em data/content-axis-results.yml, e é por isso que um eixo pode ser medido enquanto todo formato ainda está com n = 0. Não especule sobre o que tal formato é — o rótulo diz deliberadamente nada sobre ele.

Regras de honestidade

Estas não são preferências de estilo. O repositório não vale nada se elas forem quebradas.

  1. n: 0 significa não testado. Nunca arredonde para "promissor" ou "provável".
  2. Abaixo de n=5 é uma direção, não um resultado. Diga qual você está dando.
  3. Formatos perdedores permanecem listados com seus números. Não os descarte silenciosamente.
  4. Nunca escreva data.yml manualmente. Apenas kw measure apply o escreve. Números digitados de memória são indistinguíveis de números que foram inventados.
  5. Nunca misture um número de formato com um número de eixo. Veja a tabela acima.
  6. Todo número na tela precisa de uma fonte. Um clipe que você gera carrega ou sampleContent: sourced com uma URL, ou placeholder com texto de preenchimento óbvio. Inventar uma estatística plausível para uma demonstração é a mesma falha que inventar um número de retenção.
  7. Os dados iniciais são o canal de um criador. É um ponto de partida, não uma lei da plataforma. Diga de quem é a amostra quando a distinção for importante.

Arquivos de referência

  • references/spec.md — a referência de elemento e animação do format.json
  • references/formats.md — a biblioteca de formatos, por família, com hipóteses
  • references/measuring.md — exportação CSV, mapeamento e o ciclo de relatório
  • references/authoring.md — escrevendo um novo formato que vale a pena medir

Habilidades Relacionadas