Demo aufnehmen
Nimmt ein Walkthrough auf, das wie eine Person aussieht, die die App benutzt – geschwungene Cursor-Pfade, Tastenanschlag-für-Tastenanschlag-Tippen, bewusste Pausen – anstatt wie eine Maschine, die durch die UI teleportiert.
Die folgenden Regeln gelten für jede Aufnahme, auf jeder Oberfläche. Sie stehen hier und nicht in den Plattform-Referenzen, weil jede Regel schon einmal gebrochen wurde und einen Take gekostet hat, und weil eine Regel, die nur neben einem Mechanismus steht, eine Regel ist, die die nächste Person nicht liest.
Wähle die Oberfläche
- Die Web-App – reference/web.md. Headless Chromium unter Playwright mit einem DOM-Cursor, der in die Seite gezeichnet wird. Nichts erreicht den Bildschirm des Bedieners. Bevorzuge dies immer, wenn die Änderung in einem Browser sichtbar ist.
- Die Desktop-App – reference/desktop.md. Erforderlich, wenn die Demo die echte Electron-Shell benötigt: native Menüs, Datei-Dialoge, Tray, mehrere Fenster oder alles außerhalb des Renderers. Linux hat einen gebündelten Runner; macOS zeichnet ein einzelnes Fenster per ID auf und hat noch keinen Runner.
Wenn die Änderung auf beiden sichtbar ist, nimm die Web-App auf.
Eingaben
Lege diese vor dem ersten Take fest. Lies sie aus dem Projekt, wo du kannst (aus dessen README, package.json-Skripten,
dem Electron-Hauptprozess); frage den Benutzer nach allem, was du nicht finden kannst, anstatt zu raten.
- Web: die URL der laufenden App, die dem Rekorder als
PR_RECORDER_BASE_URLübergeben wird (z.B.http://localhost:3000). Die App muss bereits aus dem Checkout laufen, das die Änderung enthält, einschließlich uncommitteter Änderungen – ein frischer Checkout desselben Branches hat sie nicht, und git weigert sich, einen Branch zweimal auszuchecken. Sie muss außerdem in dem Zustand sein, den die Demo benötigt. Wenn der Ablauf einen angemeldeten Benutzer oder vorbereitete Daten erfordert, ist das die Aufgabe des Projekts, dies bereitzustellen, nicht die des Rekorders – aber bestätige es vor dem Aufnahmestart, sonst bekommst du einen Take eines Anmeldebildschirms. - Desktop:
DEMO_APP_DIR– das Verzeichnis, in dem der Startbefehl der App ausgeführt wird.DEMO_WINDOW_TITLE– der genaue Titel des Hauptfensters, verwendet, um sowohl das X11-Fenster als auch die Renderer-Seite zu finden.DEMO_LAUNCH_CMD– optional. Ein Shell-Befehl, der die App mit Remote-Debugging auf{port}startet. Der Standardwertpnpm dev --remoteDebuggingPort {port} --noSandboxpasst zu electron-vite.
Wo das Skill lebt
<skill-dir> in dieser Dokumentation bedeutet das Verzeichnis, aus dem diese SKILL.md geladen wurde. In Claude Code
ist es ${CLAUDE_SKILL_DIR}, was sowohl für Projekt-, persönliche als auch Plugin-Installationen funktioniert. Andernorts
verwende den Pfad, aus dem das Skill geladen wurde – für Codex ein Ordner .agents/skills/record-demo im Repository
oder ~/.agents/skills/record-demo. Löse es einmal auf und verwende den absoluten Pfad; die Skripte gehen nie davon aus,
wo das Skill installiert ist.
Probe vor dem Take, der zählt
Führe den gesamten Ablauf von Anfang bis Ende durch, bevor du den Take aufnimmst, den du ausliefern wirst. Eine Demo wird entdeckt, nicht geschrieben: Steuerelement-Namen sind nicht das, was du erwartest, ein Button tut etwas anderes, als sein Name sagt, und eine Oberfläche braucht länger, um sich zu beruhigen, als du geschätzt hast. Das auf Kamera herauszufinden, bedeutet, dass der Zuschauer zusieht, wie du es herausfindest.
Proben sind billig und Wiederholungen sind billig. Einen Take mit einem falschen Abzweig auszuliefern oder den Reviewer zu bitten, die mittleren acht Sekunden zu ignorieren, ist das nicht.
Überprüfe zuerst die echten Steuerelement-Namen
Skripte niemals gegen ein Steuerelement schreiben, von dem du nicht bestätigt hast, dass es existiert und das tut, was sein Name vermuten lässt. Lade die App einmal, gib die zugänglichen Namen aus und mache einen Screenshot:
const names = await page
.getByRole("button")
.evaluateAll((els) =>
els.map((e) => (e.getAttribute("aria-label") || e.textContent || "").trim()).filter(Boolean),
);
console.log(JSON.stringify(names));
await page.screenshot({ path: "/tmp/probe.png" });
Lies dann den Screenshot. Der Auszug sagt dir, dass ein Name existiert; nur das Bild sagt dir, was das Steuerelement ist. Vier Arten, wie das beißt:
- Ein Name, der nicht das ist, was du vermuten würdest. Der zugängliche Name eines Umschalters war der Name des derzeit ausgewählten Elements, nicht "Projekt auswählen".
- Ein Name, der nicht das ist, wonach er klingt. Ein
Dateien-Button in einer Seitenleiste war ein Abschnitts-Umschalter, sodass das Anklicken den Abschnitt einklappte, anstatt irgendwohin zu navigieren. Das wurde in einen Take ausgeliefert. - Ein Name, der Teil eines anderen Namens ist.
getByLabel("Erste Nachricht")traf auch auf eine nahegelegene Option zu, deren Label "erste Nachricht" enthielt, sodass die Eingabe nie das Feld erreichte und nichts fehlschlug. Verwendeexact: trueoder stimme zusätzlich auf die Rolle ab. - Etwas, das wie Text aussieht, aber keiner ist. Eine Auswahl-Überschrift, die von einem Screenshot abgelesen wurde,
war ein Platzhalter eines Eingabefelds, sodass
getByTextsie nie finden konnte. Bestätige, dass ein Locator aufgelöst wird, bevor du dagegen ein Skript schreibst.
Wenn mehrere Elemente einen Namen teilen – ein Element erscheint in der Seitenleiste, der Seitenkopf und einem
Breadcrumb – begrenze mit .first().
Treibe es so an, wie es eine Person tun würde
Finde Steuerelemente anhand der sichtbaren Rolle oder des sichtbaren Textes (getByRole, getByText, getByLabel,
getByPlaceholder). Niemals CSS-Selektoren, niemals test-only-Attribute und niemals einen Hook in die App einbauen,
damit eine Aufnahme etwas finden kann. Demo-Skripte sind Einweg- und PR-bezogen; halte sie außerhalb des Repositorys.
Ändere niemals die App, das Skill oder den Produktionscode für eine Demo. Wenn die Demo eine andere App benötigt, ist die Demo falsch.
Warte niemals auf die Uhr
waitForTimeout(9000), um "den Editor laden zu lassen", ist der mit Abstand häufigste Grund für ansehbare, aber
langweilige Demos. Es zahlt immer den schlimmsten Fall, und jede dieser Sekunden ist in der Datei. Warte auf das Ding,
auf das du tatsächlich wartest – das erste Steuerelement, mit dem du interagieren wirst – damit die Demo in dem Moment
weitergeht, in dem die App bereit ist, und laut fehlschlägt, den Locator nennt, anstatt eine halb aufgebaute Seite
zu bedienen.
Feste Pausen sind nur für das Tempo da: ein Schlag nach einer Aktion, damit ein Zuschauer aufnehmen kann, was sich geändert hat. Sekunden, nicht zehn Sekunden, und niemals als Ersatz für ein Warten.
Eine geschriebene Datei ist kein Beweis
Rekorder spülen eine partielle Datei, wenn das Skript einen Fehler wirft, und einige Aufnahmewerkzeuge schreiben beim Beenden, was immer passiert ist. Die Existenz der Datei allein sagt also nichts aus. Bevor du einem Take glaubst:
- Überprüfe den Exit-Status und stderr und lies den Fehler, falls es einen gibt – er nennt meist den Locator, der nichts gefunden hat.
- Überprüfe auf eine veraltete Aufnahme, die bereits den Ausgabepfad hält. Eine Aufnahme, die von einem früheren Versuch noch läuft, besitzt immer noch den Dateinamen und wird stillschweigend eine Aufnahme der falschen Sache produzieren.
- Überprüfe die Frames. Extrahiere ein Kontaktblatt, den letzten Frame und jeden Übergang, bei dem du unsicher bist, und sieh sie dir an.
Überprüfe die Demo, nicht das Skript
Ein sauberer Exit sagt, dass das Skript gelaufen ist, nicht dass die Funktion funktioniert hat. Bestätige beides:
- Visuell – die Änderung ist in den Frames auf dem Bildschirm, in dem Zustand, den die Anfrage verlangt hat.
- Funktional – der persistierte Zustand hat sich tatsächlich geändert, aus der Datenbank oder der API gelesen, nicht aus der UI geschlossen.
Wenn die Behauptung das Layout betrifft – zwei Bereiche nebeneinander, ein Panel an eine Kante angedockt –, behaupte es aus den Bounding-Boxen. Dass Elemente existieren, sagt nichts darüber, wo sie sind.
Halte den Endzustand etwa drei Sekunden lang, damit der Zuschauer darauf landet, dann überprüfe den Codec, die
Abmessungen und die Dauer der Ausgabedatei mit ffprobe, bevor du sie übergibst.
Bewahre die Beweise auf
Bewahre Fehlerprotokolle, Teil-Takes und Screenshots auf, bis ein Take erfolgreich war. Lösche flüchtigen Zustand erst, nachdem du etwas hast, das du ausliefern würdest. Ein verworfener Zwischenschritt ist oft die einzige Aufzeichnung warum der Take schiefging.
Störe nicht den Rechner, auf dem du aufnimmst
Eine lokale Aufnahme läuft auf dem tatsächlichen Computer einer Person, während sie ihn benutzt.
- Gib der App ein eigenes einmaliges Profil und berühre niemals das echte Profil des Bedieners.
- Bereite alles vor, was die Demo benötigt, bevor der erste Start erfolgt, sonst erscheinen Einrichtungsbildschirme vor ihnen.
- Kontrolliere jeden Prozess, den du startest, und stoppe ihn, wenn du fertig bist – insbesondere Aufnahmen, die weiterlaufen, nachdem das Skript zurückgekehrt ist.
- Starte langlaufende Prozesse als Hintergrundaufgaben, für die du ein Handle hältst, nicht mit einem nachgestellten
&innerhalb eines Vordergrund-Wrappers: Wenn der Wrapper beendet wird, nimmt er den Server mit. - Stoppe einen Prozess so, wie er erwartet, gestoppt zu werden. Ein Development-Server, der mit SIGKILL getötet wurde,
übersprang seinen Cleanup-Trap und hinterließ eine neu geschriebene Env-Datei und eine veraltete Port-Datei. Signaliere
den Prozess, den du gestartet hast, und lass ihn aufräumen. Niemals mit Muster töten (
pkill -f next): Auf einem gemeinsamen Rechner löscht das auch die Server anderer Leute. - Überprüfe, mit welchem Backend die App unter Demo spricht. Ein Entwicklungsstarter standardmäßig auf eine Produktions-API, wenn nicht anders angegeben, sodass die Klicks einer Demo echte Daten geschrieben hätten. Richte es vor dem ersten Take auf ein lokales oder Entwicklungs-Backend aus.
- Prüfe alles Externe, auf das die Demo angewiesen ist – eine CLI, die angemeldet sein muss, einen Dienst, der verfügbar sein muss –, bevor du ein Display nimmst oder die Aufnahme startest, damit eine fehlende Abhängigkeit in einer Sekunde fehlschlägt, nicht mitten im Take. Führe niemals eine Aktion mit Seiteneffekten aus, z. B. das Senden einer Nachricht, nur um zu beweisen, dass ein Werkzeug gestartet wurde.
- Wenn ein Take ihren Bildschirm, ihren Fenstermanager oder ihre Eingabe benötigt, sage das und frage, anstatt es einfach zu nehmen.
Die Datei auf einen PR bekommen
gh lädt das Video selbst hoch, seit v2.99.0:
gh pr comment <number> --body-file ./note.md --attach ./demo.mp4
--attach funktioniert auch bei gh pr create, gh pr edit und den entsprechenden gh issue-Befehlen. Es ist
wiederholbar, bis zu 50 Dateien pro Befehl, und lädt auf das user-attachments-CDN hoch, sodass GitHub das Video
inline rendert.
Vier Dinge, die wissenswert sind:
- Alt-Text ist nur für Bilder.
'./shot.png#The error state'setzt Alt-Text auf einem Bild; die gleiche Syntax wird bei einem Video mitcannot set alt text on videoabgelehnt. Hänge Videos mit einem bloßen Pfad an. - Ein Body, der bereits den lokalen Pfad referenziert, wird umgeschrieben. Schreibe
an die Stelle, an der es sein soll, undghtauscht die hochgeladene URL ein; andernfalls wird der Anhang an das Ende angehängt. gh pr edit --attachohne Body-Flag behält den vorhandenen Body und hängt an ihn an, sodass eine Demo nachträglich zur PR-Beschreibung hinzugefügt werden kann.- Überprüfe die Version, bevor du dich darauf verlässt. Bei
ghälter als 2.99.0 gibt es kein--attachund das CDN ist auf keinem anderen Weg durch die API erreichbar – falle also darauf zurück, der Person den Dateipfad zu geben, damit sie ihn selbst in den PR ziehen kann.