AppLoidx/record-demo

Compétence d'agent / projet lié à la création de vidéos de démonstration ou de lancement de produit : AppLoidx/record-demo

Qu'est-ce que record-demo ?

Cette compétence d'agent permet de créer enregistrer et éditer des vidéos de démonstration de produits ou d'applications en utilisant un moteur basé sur Playwright. L'agent écrit un storyboard ad-hoc dans un DSL dédié spécifie les actions de navigation les zooms sur des éléments les légendes et les transitions. Le moteur autonome exécute ce storyboard contre une URL cible et produit plusieurs formats vidéo (16x9 1x1 9x16) ainsi qu'un GIF animé. Le processus inclut la vérification de la fraîcheur du code serveur la gestion de l'authentification via des sessions temporaires et une édition avancée dans Remotion Studio. La compétence impose des règles de montage strictes (un mouvement de caméra par scène attente de données réelles légendes impératives) et une batterie de tests de validation pour garantir la qualité des clips produits.

Compatible avec✓Claude Code~Codex CLI✓Cursor
npx skills add AppLoidx/record-demo

Installed? Explore more Développement et programmation skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Enregistrer des vidéos de démonstration

Rédigez un storyboard Playwright ad-hoc, puis exécutez le moteur autonome depuis n'importe quel répertoire de travail. N'ajoutez pas le storyboard à un dépôt d'application sauf si l'utilisateur le demande. Gardez le storyboard autonome ; l'exécuteur place ce fichier dans le moteur avant que Playwright ne le charge, ne faites donc pas d'imports d'utilitaires relatifs au storyboard. <skill-dir> désigne le répertoire où ce dépôt est cloné, par exemple ~/.claude/skills/record-demo.

Rédiger le storyboard

Importez le DSL avec cet import portable :

import { demo } from "record-demo/storyboard";

L'exécuteur réécrit ce spécificateur vers le chemin réel du moteur lors de la mise en scène, de sorte que le fichier storyboard peut se trouver n'importe où. La résolution de type dans l'éditeur pour record-demo/storyboard provient de paths dans engine/tsconfig.json - en dehors du dépôt, mappez record-demo/storyboard vers le chemin absolu <skill-dir>/engine/lib/storyboard.ts dans vos paths tsconfig, ou gardez le fichier dans engine/scripts/.

Utilisez engine/scripts/example-site.demo.ts comme référence. Préférez les sélecteurs getByRole, utilisez d.click(locator) au lieu de locator.click(), rythmez les actions avec d.hold(...), et affirmez ou attendez l'état final.

demo("titre-du-storyboard", async (d) => {
  await d.seed(async (page) => {
    await page.getByRole("heading", { name: "Exemple de domaine" }).waitFor();
  });

  await d.step("Lire la page", async (page) => {
    const heading = page.getByRole("heading", { name: "Exemple de domaine" });
    await d.zoomTo(heading, { padding: 48 });
    await d.hold(2_000);
    d.zoomOut();
    await heading.waitFor({ state: "visible" });
  });
});

Le moteur remplace le nom de la timeline par --name ou le nom de base du script, donc la chaîne passée à demo(...) n'a pas besoin de correspondre au slug de sortie.

Pré-vol (avant toute capture)

Lors de l'enregistrement contre un checkout servi localement : git fetch origin dans le checkout de service et affirmez que HEAD == origin/main (ou la branche nommée par l'utilisateur) — un checkout périmé enregistre un design périmé. S'il est périmé, reconstruisez/redémarrez d'abord le serveur. Imprimez le SHA de service dans les notes de prise afin que chaque enregistrement soit attribuable.

Enregistrer

Nécessite Node >= 22.18 (nvm ou système), ffmpeg, Xvfb et xdpyinfo. Installez les dépendances une fois dans engine/ avec pnpm install.

node <skill-dir>/engine/record.mjs \
  --script /chemin/absolu/ou/relatif-au-répertoire-courant/demo.demo.ts \
  --url https://example.org \
  [--name slug-de-sortie] [--formats 16x9,1x1,9x16] \
  [--chrome none|macos|browser] [--storage-state <chemin>] [--raw]

Utilisez --formats pour sélectionner un ou plusieurs préréglages de composition (par défaut 16x9) et --chrome pour choisir le cadre de fenêtre rendu (par défaut none). Les formats sont rendus dans l'ordre demandé, et le premier est le principal utilisé pour encoder le GIF. Le format 9x16 est un recadrage agressif centré (environ 44 % de la largeur de la page est visible dans le plan large), donc gardez l'action centrée lors de la rédaction pour le portrait.

Utilisez --raw pour vous arrêter après la capture propre. Sans cela, attendez-vous aux livrables suivants :

  • engine/out/<nom>-raw.mp4
  • engine/out/<nom>-<format>.mp4 pour chaque format demandé
  • engine/out/<nom>.gif encodé à partir du format principal

L'exécuteur affiche les chemins absolus des livrables une fois terminé. Traitez la reproductibilité du site en direct comme étant la responsabilité du site cible et n'intégrez jamais de véritables identifiants dans un storyboard.

Sites authentifiés

Enregistrez les flux authentifiés uniquement avec des comptes de staging ou de test ; n'utilisez jamais les identifiants de production. L'agent doit d'abord se connecter une fois avec ses propres outils, en utilisant un script Playwright sans tête. Si la connexion nécessite un OTP envoyé par e-mail ou un lien magique, la voie préférée est l'accès au courrier de l'agent lui-même - un connecteur Gmail/MCP connecté sur Claude Code, ou un CLI de messagerie sur d'autres runtimes - afin qu'il lise le code lui-même ; sinon, demandez à l'utilisateur de le coller. Après la connexion, enregistrez la session avec await context.storageState({ path: storageStatePath }), où storageStatePath est un chemin temporaire à usage unique créé comme storageStatePath="$(mktemp -d)/<compte>.storage-state.json". Exécutez ensuite la commande d'enregistrement avec --storage-state "$storageStatePath".

Playwright storageState restaure uniquement les cookies et le localStorage. Les applications qui conservent l'authentification dans IndexedDB ou sessionStorage enregistreront silencieusement un écran de déconnexion, donc vérifiez la page authentifiée avant la capture. Le fichier storage-state est un secret : ne l'imprimez ou ne le validez jamais. L'enregistreur le supprime immédiatement après l'avoir chargé ; c'est un transfert à usage unique, donc une nouvelle capture nécessite une nouvelle connexion et rien de lié à l'authentification n'est laissé sur le disque. Le script d'aide à la connexion unique contient également des identifiants : gardez-le temporaire et ne le validez jamais.

Modifier une démo enregistrée dans Remotion Studio

Exportez un projet autonome après l'enregistrement, puis installez et ouvrez Studio :

node <skill-dir>/engine/scripts/export-project.mjs <nom>
cd <skill-dir>/engine/out/<nom>-project
pnpm install
pnpm studio

Le panneau de la timeline de Studio affiche des pistes de style éditeur (bande-annonce d'écran, un clip nommé par légende, projecteur, mouvement de zoom et outro) - faites glisser la tête de lecture pour parcourir, cliquez sur la ligne d'un clip pour trouver son événement. Utilisez le panneau des propriétés ou fixtures/timeline.json pour modifier les légendes, le timing des zooms (gardez les mouvements de zoom à ou au-dessus du seuil de 1650ms), le timing du projecteur, et le titre de l'outro. Modifiez remotion/theme.ts pour les couleurs, la typographie, l'espacement et le mouvement. Rendez la vidéo 16:9 terminée avec pnpm render.

Règles de mouvement et de storyboard (ce qui rend un clip publiable)

  • Un seul mouvement de caméra par scène, pas par champ. Zoomez une fois sur la section, agissez à l'intérieur. Les zooms par entrée ressemblent à des coupes brusques.
  • Plan large lors des transitions de page, restez large sur les pages peu denses. d.zoomOut() AVANT un clic qui navigue ; ne zoomez jamais sur une pastille d'état sur une page presque vide.
  • Sections près du bas de la page : d.zoomTo([...locators], { scroll: "center", padding: 48 })
    • le bloc de la caméra ne peut pas centrer un rectangle en bord de page ; le centrage par défilement le corrige à la racine. Locator[] encadre une section entière via le bbox d'union.
  • d.spotlight([...locators]) = mise au point de style Apple (découpe + anneau). Généreux holdMs, terminez explicitement par d.spotlightOff() + hold(600) avant la fin de l'étape. Les rectangles du projecteur doivent tenir dans la fenêtre (appliqué) ; les rectangles de zoom peuvent déborder par conception.
  • Seed attend les données réelles, pas seulement l'élément déclencheur - sinon la vidéo s'ouvre sur un squelette. Attendez un nœud de contenu connu + ~600 ms.
  • d.settle(locator) avant les légendes de résultat. Les vues qui récupèrent après une soumission se vident brièvement ; un simple waitFor se résout sur la première peinture et la légende de résultat se déclenche sur une page blanche.
  • Les légendes sont des impératifs liés à l'action du curseur ; mettez une légende de résultat (d.caption(...) tard dans l'étape) sur les scènes de clôture ; réduisez les légendes des étapes pour que les impératifs ne pendent jamais sur des actions terminées.
  • d.outro(titre) ferme les clips publiable avec une dalle de fin calme après la scène finale.
  • Affirmez toujours l'état final - sans cela, le pipeline rend une vidéo soignée d'un flux cassé.
  • N'expédiez jamais un clip avec une URL localhost, un nom d'hôte interne, un nom de fournisseur ou de véritables identifiants à l'écran. Masquez les chaînes de présentation uniquement dans la seed (un patch window.open et une réécriture d'entrée MutationObserver).

Vérifier avant de signaler terminé

  1. pnpm typecheck && pnpm test dans engine/.
  2. node scripts/score-motion.mjs out/timeline.json - FAIL bloque ; WARN taux de zoom ~0.78/s est l'état stable accepté ; tout verdict de discontinuité est un bug de caméra ; les WARN de silence mort signifient un étirement statique >= 3,5 s avec moins de 40 px de déplacement du curseur - re-rythmez ou légendez-le.
  3. node scripts/prove-composition.mjs après les modifications du moteur.
  4. Regardez le rendu réel : ffmpeg -i out/<nom>-16x9.mp4 -vf fps=1 out/frames/%03d.png et lisez les images. Le clipping du zoom, le décalage des légendes, la désynchronisation de la découpe et les URL de développement à l'écran sont invisibles dans un test vert.
SymptômeCause / correctif
Abandon Invalid demo viewport ...La géométrie a dérivé - corrigez les indicateurs de lancement, n'assouplissez jamais l'assertion.
Décalage du curseur d'environ 174 px verticalementChrome s'est exécuté en onglets, pas en --app.
Impossible de trouver les images de clapLa tolérance du détecteur est de 64 (les captures externes sont en moyenne impures) ; s'il manque toujours, vérifiez que la capture n'est pas noire (Chrome sur le mauvais DISPLAY).
Décalage des légendes/curseur sur le clipSynchronisation du clap - ne soustrayez pas l'horloge murale.
Découpe du projecteur manquant sa cibleLe rectangle a dépassé un défilement fluide - la boucle de stabilité de measureTarget devrait tenir ; si cela se reproduit, augmentez son délai d'attente.
Mots coupés au milieu d'une lettre au bord du recadragezoomTo(locator, { padding: 120 }) pour les modales.
Le zoom coupe le contenu du cadreProblème de goût maximumScale (1,45 fonctionne), pas un bug de blocage.

Vérifier les modifications du moteur

Exécutez depuis engine/ :

pnpm typecheck && pnpm test
node scripts/prove-composition.mjs

Skills associés