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
KWem cada comando ou inicie cada um com umcd /caminho/absoluto/para/keepwatching &&explícito. Não presuma que$KWsobrevive. npm run setuppode 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ília | Comece com |
|---|---|---|
| um grande número | stat-counter | stat-counter-rise |
| uma recompensa que vale a espera | countdown | countdown-clock |
| um conjunto ordenado de itens | ranking | ranking-suspense (conclusão) ou ranking-reveal (compartilhamentos) |
| duas opções que diferem em um número | comparison | split-compare |
| o mesmo sujeito em dois estados | reveal | before-after |
| uma crença falsa generalizada | myth-fact | myth-vs-fact |
| uma frase forte | cold-open | cold-open-line |
| um processo com estágios reais | progress | progress-bar |
| valores que realmente escalam | escalation | escalation-ladder |
| algo circular | reverse | loop-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.durationSece cada tempo na cena pornovaDuracao / 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:
| campo | 10s | ×3 | enviado |
|---|---|---|---|
canvas.durationSec | 10 | 30 | 30 |
counter endSec | 6,4 | 19,2 | 21,0 |
bar endSec | 6,4 | 19,2 | 21,0 |
unit at | 6,4 | 19,2 | 21,0 |
context at / in.at | 6,5 | 19,5 | 21,6 |
source at | — | — | 25,5 — um batida que não existia |
posterSec | 8,4 | 25,2 | 27,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 × fpsdeve ser um número inteiro de quadros.- Aumente
versionemformat.jsonsempre que alterar a cena — reajuste de tempo conta. Um esqueleto novo em0.1.0que você depois reajusta se torna0.2.0. O id da variante deriva deversionmais um hash da especificação, então isso mantém uma medição futura atribuível. npx kw checkcaptura tempos além do final do clipe, enpx kw frame0captura 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, abraout/<slug>/contact.pngapó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:
| Bloco | Pergunta | Classifica a biblioteca? |
|---|---|---|
format | Como esta estrutura de cena se comporta? | Sim |
content_axis | Como 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-clockreteve 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.
n: 0significa não testado. Nunca arredonde para "promissor" ou "provável".- Abaixo de n=5 é uma direção, não um resultado. Diga qual você está dando.
- Formatos perdedores permanecem listados com seus números. Não os descarte silenciosamente.
- Nunca escreva
data.ymlmanualmente. Apenaskw measure applyo escreve. Números digitados de memória são indistinguíveis de números que foram inventados. - Nunca misture um número de formato com um número de eixo. Veja a tabela acima.
- Todo número na tela precisa de uma fonte. Um clipe que você gera carrega ou
sampleContent: sourcedcom uma URL, ouplaceholdercom 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. - 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 doformat.jsonreferences/formats.md— a biblioteca de formatos, por família, com hipótesesreferences/measuring.md— exportação CSV, mapeamento e o ciclo de relatórioreferences/authoring.md— escrevendo um novo formato que vale a pena medir