Que fait keepwatching ?
Une base de données de formats vidéo courts nommés qui effectue le rendu. Chaque format est composé de trois fichiers : une spécification de rendu, une hypothèse énoncée, et ce que les mesures indiquent — y compris "rien pour l'instant".
La règle qui rend cette compétence utile : ne jamais inventer un chiffre de rétention. Chaque affirmation sur les performances d'un format provient de formats/<slug>/data.yml, et chacune porte un n. Si n: 0, la réponse honnête est "non testé" — dites-le.
Configuration — faites ceci en premier, à chaque session
Cette compétence pilote un véritable moteur de rendu qui se trouve dans le dépôt keepwatching. Les instructions seules ne peuvent rien rendre, donc la première étape est toujours de localiser ou d'installer le dépôt.
# 1. Trouvez-le. La première correspondance gagne ; demandez à l'utilisateur si aucun de ceux-ci n'existe.
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. Installation unique. Sans danger à réexécuter ; il ne fait rien si déjà fait.
npm install && npm run setup
# 3. Confirmez que la bibliothèque est intacte avant de faire quoi que ce soit d'autre.
npx kw check
Les 24 aperçus de la galerie sont commités, donc npx kw gallery affiche la page en quelques secondes sans rien rendre. npm run setup n'est nécessaire que pour rendre la vidéo. Si vous modifiez la scene d'un format, son aperçu commité devient obsolète — re-rendez et commitez-le avec npx kw gallery --no-serve && git add site/previews, sinon le CI kw previews check échouera.
kw check affichant no problems signifie que vous êtes prêt. S'il signale des polices manquantes, réexécutez npm run setup — la composition refuse de rendre avec une police de secours, car une police substituée changerait silencieusement chaque image que le dépôt a jamais mesurée.
Deux notes pratiques.
- Les variables shell ne persistent pas entre les appels d'outils dans la plupart des environnements d'agent. Soit recalculez
KWdans chaque commande, soit commencez chacune par uncd /chemin/absolu/vers/keepwatching &&explicite. Ne supposez pas que$KWsurvit. npm run setuppeut prendre plusieurs minutes sur une machine froide. Il télécharge Inter (≈30 Mo) et un Chromium sans tête (≈150 Mo). Sur une machine qui a déjà les deux en cache, cela se termine en quelques secondes. Dites à l'utilisateur ce qui se passe plutôt que de sembler bloquer.
Chaque commande de ce fichier suppose que la racine du dépôt est le répertoire de travail. Si l'utilisateur travaille dans un autre projet, effectuez le rendu dans le dépôt et copiez le MP4 ; kw ne fonctionne pas depuis l'extérieur.
Il y a aussi npm run check, qui est kw check plus tsc --noEmit. Utilisez-le si vous avez modifié quoi que ce soit dans engine/.
Les quatre choses que l'on vous demandera de faire
1. Choisir un format pour un sujet
npx kw list # tous les formats, avec leur taille d'échantillon et leur rétention mesurée
Lisez formats/<slug>/meta.yml pour l'hypothesis, le useWhen et le avoidWhen. Faites correspondre la forme du contenu à la famille de formats, pas au sujet.
Chaque format dans le tableau ci-dessous a actuellement
n = 0. Ce sont des points de départ choisis à partir d'une hypothèse énoncée, pas des gagnants choisis à partir de preuves. Dites-le lorsque vous en recommandez un. Le tableau vous indique quel format prétend convenir à une forme de contenu ; il ne vous dit pas lequel performe.
| Le contenu est… | Famille | Commencez par |
|---|---|---|
| un grand nombre | stat-counter | stat-counter-rise |
| un résultat qui vaut la peine d'attendre | countdown | countdown-clock |
| un ensemble ordonné d'éléments | ranking | ranking-suspense (achèvement) ou ranking-reveal (parts) |
| deux options qui diffèrent sur un nombre | comparison | split-compare |
| le même sujet dans deux états | reveal | before-after |
| une fausse croyance répandue | myth-fact | myth-vs-fact |
| une phrase forte | cold-open | cold-open-line |
| un processus avec des étapes réelles | progress | progress-bar |
| des valeurs qui montent réellement | escalation | escalation-ladder |
| quelque chose de circulaire | reverse | loop-seam |
Lorsque vous en recommandez un, citez son n. "ranking-suspense, bien qu'il soit non testé dans ce dépôt (n=0)" est une bonne recommandation. "ranking-suspense obtient 68% de rétention" est une fabrication sauf si data.yml le dit.
2. Rendre une vidéo
Copiez un format, remplissez le bloc data, effectuez le rendu :
npx kw new my-clip --from=stat-counter-rise
# modifiez formats/my-clip/format.json -> "data": { ... }
npx kw render my-clip # -> out/my-clip/master.mp4
# Facultatif : prévisualisez-la dans un navigateur d'abord, sans encoder quoi que ce soit.
# Bloque jusqu'à ce que vous l'arrêtiez, donc sautez cette étape en mode non supervisé.
npx kw preview my-clip
Modifiez uniquement data sauf si la disposition doit vraiment changer. Le tableau scene est le format ; le modifier fait du clip un format différent, et ses mesures ne sont plus transférables. Si vous modifiez la scène, augmentez la version dans format.json — l'identifiant de variante en découle.
Modification de la durée — lisez ceci, c'est la demande la plus courante.
Les formats de la bibliothèque durent 8 à 30 secondes (21 sur 24 entre 8 et 14). Les trois de 30 secondes — cold-open-question, countdown-clock, stat-counter-rise — sont les niveaux d'une expérience en cours, pas la durée standard. Toute durée qu'un format n'a pas déjà nécessite la modification de la scène, donc "modifiez uniquement data" ne s'applique pas. Utilisez cette règle :
Multipliez
canvas.durationSecet chaque temporisation dans la scène parnewDuration / oldDuration. Ensuite, regardez la fin : la mise à l'échelle étire la tenue finale par le même facteur, donc plus le facteur est grand, plus la fin est mauvaise.
Exemple concret — stat-counter-rise de 10s à 30s, facteur 3.0. Ce sont les nombres qui ont réellement été livrés, pas une illustration :
| champ | 10s | ×3 | livré |
|---|---|---|---|
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 — un temps qui n'existait pas |
posterSec | 8.4 | 25.2 | 27.5 |
La mise à l'échelle seule a laissé le dernier temps à 19,5 s dans un clip de 30 secondes : 10,5 secondes d'une carte figée. Le pousser à 21,6 n'a pas non plus suffi. Au-delà d'un facteur d'environ deux, l'arithmétique cesse d'être la réponse — le clip a besoin d'un temps qu'il n'avait pas. Ici, il s'agit d'une ligne de citation à 25,5 s, que le format revendiquait dans ses sources depuis le début sans jamais l'afficher à l'écran. Tenue finale : 4 secondes.
Une carte finale maintenue plus d'environ 3 secondes est un vide sonore, et un vide sonore à la fin est ce qui tue un taux d'achèvement. kw frame0 échoue carrément à 5 secondes d'un écran immobile : 3 est le conseil artisanal, 5 est le plancher dur. Il a trouvé trois formats qui avaient déjà été livrés avec une fin figée de 6 secondes.
Contraintes et vérifications :
durationSec × fpsdoit être un nombre entier d'images.- Augmentez la
versiondansformat.jsonchaque fois que vous modifiez la scène — le réajustement temporel compte. Une nouvelle échafaudage à0.1.0que vous réajustez devient0.2.0. L'identifiant de variante dérive deversionplus un hachage de la spécification, ce qui permet d'attribuer une future mesure. npx kw checkdétecte les temporisations au-delà de la fin du clip, etnpx kw frame0détecte une première image qui n'affiche rien ainsi que toute séquence immobile de plus de 5 secondes. Aucun des deux ne peut vous dire qu'un clip est ennuyeux — pour cela, ouvrezout/<slug>/contact.pngaprès le rendu. Il échantillonne six images uniformément réparties sur le clip, donc les tuiles quasi identiques sont visibles en un coup d'œil.
Sourçage. kw new --from=<slug> réinitialise délibérément l'échafaudage à sampleContent: placeholder et supprime les sources du parent — les citations du parent étayaient les nombres du parent, pas les vôtres. Si vous mettez un vrai nombre à l'écran, définissez sampleContent: sourced et ajoutez une entrée sources: avec une URL et l'affirmation exacte qu'elle étaye.
Un nombre sourcé n'est sourcé qu'une fois qu'il atterrit. Si vous animez un compteur vers un chiffre cité, marquez-le claim: "final" et gardez l'unité et tout mot comme "exactement" hors écran jusqu'à endSec — affichez "comptage…" jusqu'alors. Chaque autre élément visible pendant le comptage a besoin de neutralWhileCounting: true. kw check refuse autrement le format. Les compteurs dont les valeurs intermédiaires sont honnêtement vraies ("images jusqu'à présent") sont marqués claim: "running" et sont exemptés.
Ce qui compte comme une source : quelque chose qu'un lecteur peut ouvrir et vérifier le nombre — un article primaire ou son enregistrement permanent (DOI, PubMed), un organisme de normalisation, une agence statistique, un rapport officiel. Pas un listicle, pas un blog qui en résume un, et pas votre propre souvenir. Indiquez tout arrondi que vous avez fait pour l'écran dans le champ claim. kw check vérifie qu'une URL et une affirmation sont présentes ; il ne peut pas vérifier qu'elles sont vraies, donc cette partie vous incombe. Si vous ne trouvez pas de source, utilisez plutôt un texte de remplissage — une statistique inventée est la même erreur qu'un chiffre de rétention inventé.
Voir references/spec.md pour la référence complète de format.json.
3. Lancer un test A/B
Deux formats, même contenu, même jour :
npx kw new test-a --from=cold-open-line
npx kw new test-b --from=redacted-reveal
# mettez une copie identique dans les deux blocs data
npx kw render test-a && npx kw render test-b
npx kw variant test-a # enregistrez cette chaîne pour le téléchargement
Le variantId dans out/<slug>/variant.json est ce qui rend le résultat attribuable. Enregistrez-le par rapport à la vidéo publiée au moment du téléchargement — il est également écrit dans le commentaire de métadonnées du MP4 si vous perdez vos notes.
4. Lire les mesures en retour
# exportez les CSV depuis YouTube Studio / TikTok Analytics dans measure/inbox/
npx kw measure # ingurgitez + rapportez -> measure/report.md
npx kw measure apply # écrivez les résultats dans formats/*/data.yml
npx kw gallery # re-rendu + reconstruction de la galerie
Pas d'API, pas d'OAuth. Voir references/measuring.md pour les étapes d'exportation exactes et le format mapping.csv.
Le déterminisme est le contrat
Le même format.json produit les mêmes images, sur n'importe quelle machine, pour toujours. C'est ce qui permet d'attribuer une courbe de rétention à un format plutôt qu'à un rendu. Lors de la modification du moteur, n'introduisez jamais Date.now(), Math.random(), requestAnimationFrame, de transitions CSS ou d'animations CSS dans la composition. npx kw render <slug> --check-determinism recherche à nouveau les images dans le désordre et échoue si un pixel a bougé.
Deux mesures qui ne doivent jamais être mélangées
data.yml a deux blocs, et ils répondent à des questions différentes :
| Bloc | Question | Classe la bibliothèque ? |
|---|---|---|
format | Comment cette structure de scène performe-t-elle ? | Oui |
content_axis | Comment ce sujet performe-t-il ? | Non |
Une seule vidéo publiée porte les deux étiquettes — c'est un décompte et c'est à propos du corps. Faire la moyenne des deux produit un nombre qui ne répond à aucune des deux questions, donc ils sont stockés séparément, rapportés séparément et affichés dans des couleurs différentes dans la galerie.
Lorsque vous rapportez un résultat, dites lequel c'est :
- "
countdown-clocka retenu 62% (n=6)" — une affirmation de format. - "Les sujets personnels/corporels ont retenu 68% (n=9)" — une affirmation d'axe.
- "Les décomptes personnels/corporels ont retenu 68%" — ni l'un ni l'autre, sauf si vous dites aussi combien de vidéos, dans quels formats, et que les deux sont confondus.
measure/report.md imprime une colonne porté par pour chaque axe. Si un axe n'a jamais été porté que par un seul format, ce résultat d'axe et ce résultat de format sont les mêmes vidéos portant deux étiquettes ; dites-le plutôt que de les présenter comme deux résultats indépendants.
Les axes de contenu sont déclarés dans data/content-axes.yml et attachés à une vidéo par la colonne facultative content_axis dans measure/mapping.csv. Ce sont les axes de l'utilisateur, pas ceux de la bibliothèque — ajoutez toute distinction qu'ils testent réellement.
variant_id: not-in-library marque une vidéo publiée dont le format n'est pas dans ce dépôt. C'est un échantillon d'axe de contenu uniquement : il n'atteint jamais le tableau des formats ni aucun data.yml, et carried by le nomme pour que l'écart soit visible. Les résultats d'axe au niveau du dépôt vivent dans data/content-axis-results.yml, c'est pourquoi un axe peut être mesuré alors que tous les formats sont encore n = 0. Ne spéculez pas sur ce qu'est un tel format — l'étiquette ne dit délibérément rien à son sujet.
Règles d'honnêteté
Ce ne sont pas des préférences de style. Le dépôt est sans valeur si elles ne sont pas respectées.
n: 0signifie non testé. Ne l'arrondissez jamais à "prometteur" ou "probable".- En dessous de n=5 est une direction, pas un résultat. Dites lequel vous donnez.
- Les formats perdants restent listés avec leurs chiffres. Ne les supprimez pas discrètement.
- N'écrivez jamais
data.ymlà la main. Seulkw measure applyl'écrit. Les nombres tapés de mémoire sont impossibles à distinguer de nombres inventés. - Ne fusionnez jamais un chiffre de format avec un chiffre d'axe. Voir le tableau ci-dessus.
- Chaque chiffre à l'écran a besoin d'une source. Un clip que vous générez porte soit
sampleContent: sourcedavec une URL, soitplaceholderavec un texte de remplissage évident. Inventer une statistique plausible pour une démo est la même erreur qu'inventer un chiffre de rétention. - Les données de départ sont la chaîne d'un créateur. C'est un point de départ, pas une loi de la plateforme. Dites de qui est l'échantillon lorsque la distinction importe.
Fichiers de référence
references/spec.md— la référence des éléments et des animations deformat.jsonreferences/formats.md— la bibliothèque de formats, par famille, avec hypothèsesreferences/measuring.md— export CSV, correspondance et boucle de rapportreferences/authoring.md— rédaction d'un nouveau format qui mérite d'être mesuré