| name | tutorial |
| description | Record narrated, themeable product tutorials by driving any web app with Playwright and voicing every step with a neural TTS voice (Jenny by default). Use when the user types "/tutorial-create", "/tutorial-update", or "/tutorial-status", or asks to "record a tutorial", "make a walkthrough video", "narrated demo", "real video with voiceover", "screen recording with narration", "update the tutorial", "refresh the tutorials index", or "tutorial status". Outputs a REAL motion video of the app moving with narration (MP4), or a screenshot slideshow, or a no-ffmpeg HTML player โ all with WebVTT captions. Runs a human-gated flow: draft & APPROVE a scenario, record it with Playwright, render, show the output for APPROVAL and fix issues in a loop, then regenerate a light/dark, logo-branded index.html that switches between every tutorial. Project-agnostic โ reads ./tutorial.config.json for brand, paths and voice.
|
Tutorial โ narrated Playwright walkthroughs
Turn a plain-English goal into a narrated, themeable tutorial. Playwright drives the app while
recording the live session to video and capturing a screenshot per step; a neural voice (Jenny)
narrates each step; then you render one of three drift-free outputs โ a real motion video of
the app in motion, a screenshot slideshow MP4, or a no-ffmpeg HTML player โ each with captions, and a
branded index.html switches between all tutorials.
The flow is gated โ never record before the scenario is approved, never publish before the
tutorial is approved. Honor done = proven: show real output (a played video / a screenshot), and
never fabricate results.
Prerequisites (Node 18+, edge-tts, Playwright; ffmpeg for the motion/slideshow MP4 โ a full
build, not Playwright's webm-only bundled one) and full setup are in README.md.
All paths below are relative to the skill folder (scripts/โฆ, templates/โฆ) and the project
root (tutorial.config.json, public/tutorials/โฆ). Adjust to wherever the skill is installed.
0. One-time project setup (the "initial settings")
On the first /tutorial-* run in a repo, ensure a tutorial.config.json exists at the project root.
If it is missing, copy config.example.json, then fill it in (auto-detect where you can โ logo under
public/, dev command from package.json, base URL from the dev server):
{
"project": { "name": "My App", "baseUrl": "http://127.0.0.1:5173", "devCommand": "npm run dev" },
"brand": { "logo": "/logo.svg", "accent": "#2563eb", "accentDark": "#1e40af", "defaultTheme": "dark" },
"tts": { "voice": "en-US-JennyNeural", "tailPadMs": 600 },
"paths": { "scenariosDir": "tutorials/scenarios", "specsDir": "tests",
"outputDir": "public/tutorials", "catalogFile": "public/tutorials/catalog.json" },
"video": { "width": 1920, "height": 1080 }
}
Confirm the values with the user, then proceed. These settings are read by every mode.
Modes
The skill dispatches on the first word of its arguments (the bundled commands/ wrappers map the
literal /tutorial-create, /tutorial-update, /tutorial-status tokens onto these):
| Mode | Trigger | What it does |
|---|
| init | /tutorial-init | Ask setup questions, then write tutorial.config.json + scaffold folders. Optionally flow into create. |
| create | /tutorial-create "<free-text goal>" | Draft+approve a scenario โ record โ render โ approve โ publish. |
| update | /tutorial-update <slug> | Re-record an existing tutorial and refresh its video + index card. |
| status | /tutorial-status | Report which tutorials are recorded vs stale/missing. No recording. |
๐บ Working example to copy: examples/grekai-catalog-tour/ โ a real
narrated tour (real screenshots + real Jenny audio + a no-ffmpeg HTML player). Open its index.html.
init โ interactive setup (ask first)
When invoked via /tutorial-init, ask the user before doing anything (AskUserQuestion, one batch):
app name + base URL + dev command ยท brand (logo, accent, default theme) ยท narration voice + output folder
ยท an optional first-tutorial goal. Then copy config.example.json โ tutorial.config.json, fill it from
the answers, create the scenariosDir/outputDir, and confirm. If a first-tutorial goal was given, flow
straight into create (draft the scenario for approval). Never record before a scenario is approved.
create โ the gated pipeline
1. Draft the scenario. From the free-text goal, write <scenariosDir>/<slug>.md using
templates/scenario-template.md: a numbered step table (Action / What to show / Why / spoken
Narration), honesty notes (anything the UI can't do โ say so in narration), and acceptance criteria.
Keep narration sentences short and spoken-plain; one cue per step.
2. โ GATE 1 โ approve the scenario. Show the draft and ask the user to approve or edit. Do not
record until approved. Loop on edits.
3. Generate / extend the Playwright spec <specsDir>/<slug>.spec.ts from the approved steps,
reusing templates/test-helpers.ts (showIntro, showStep, Timeline, saveVideo,
publishManifest) and templates/example.spec.ts as the pattern. Create a context with
recordVideo (the config template already sets video: { mode: 'on' }), and for each step: drive the
UI โ on-camera caption โ screenshot into <outputDir>/<slug>-NN.png โ timeline.mark() to record when
the step starts. At the end, saveVideo() writes <outputDir>/<slug>.webm and publishManifest()
writes <outputDir>/<slug>-steps.json (with the video path + per-step atMs for the motion renderer).
4. Record. Start the app (config devCommand/baseUrl, or the project's start script), then:
npx playwright test <specsDir>/<slug>.spec.ts
The spec must go green and emit <slug>.webm + the per-step PNGs + <slug>-steps.json.
5. Render. Three formats โ a real motion video is the headline output; pick by what's installed:
- A ยท Real motion MP4 (the app actually moving + Jenny narration) โ needs
edge-tts + ffmpeg.
Synthesize the narration first (gives per-step durations), then mux it over the recorded session video:
node <skill>/scripts/synthesize-audio.mjs --manifest <outputDir>/<slug>-steps.json --out <outputDir>
node <skill>/scripts/render-motion-video.mjs --manifest <outputDir>/<slug>-steps.json \
--audio <outputDir>/<slug>-audio.json --out <outputDir>
Produces <slug>-motion.mp4 + <slug>-narration.vtt. Drift-free: each step shows real motion for
its window, and if a step's narration is longer than its clip the last frame is frozen to fit โ so the
voice is always fully audible and never desyncs. Add --dry-run --video-dur <sec> to preview the plan
without rendering. Fails hard if the output has no audio stream. No system ffmpeg? Point at any
binary with FFMPEG_BIN=โฆ (NOTE: Playwright's bundled ffmpeg is webm-only โ use a full ffmpeg, e.g.
node_modules/ffmpeg-static/ffmpeg).
- B ยท HTML player (no ffmpeg) โ needs only
edge-tts:
node <skill>/scripts/synthesize-audio.mjs --manifest <outputDir>/<slug>-steps.json --out <outputDir>
node <skill>/scripts/build-tutorial-page.mjs --steps <outputDir>/<slug>-steps.json --out <outputDir>/<slug>.html
A self-contained, themeable <slug>.html that plays the screenshots in sync with the audio
(captions + light/dark toggle). Good when ffmpeg isn't available.
- C ยท Slideshow MP4 (screenshots โ video) โ needs
edge-tts + ffmpeg:
node <skill>/scripts/render-tutorial-video.mjs --manifest <outputDir>/<slug>-steps.json --out <outputDir>
Produces <slug>-jenny.mp4 โ static screenshots held under narration. Use when there's no recorded
session video (e.g. a re-render from screenshots only).
6. โ GATE 2 โ show & approve the tutorial. Open the MP4 (or capture a Playwright screenshot of it
playing) and present it. Review honestly against the acceptance criteria; fix issues (re-narrate,
re-shoot a step, adjust timing) and re-render in a loop until the user approves.
7. Publish + theme. Upsert the tutorial into <catalogFile> ({slug,title,description,status, video,poster,recordedAt}), then regenerate the switchable, branded index:
node <skill>/scripts/build-index.mjs --catalog <catalogFile> --config tutorial.config.json --out <outputDir>/index.html
The index gets the configured logo + accent, a light/dark toggle (persisted in localStorage),
and a filter box. Report the served URL (e.g. <baseUrl>/tutorials/index.html).
update โ refresh an existing tutorial
Re-run the spec for <slug>, re-render the narration, update its recordedAt in the catalog, and
rebuild the index (step 7). Use when the UI changed or narration needs a tweak.
status โ report, don't record
Read <catalogFile> and the specs in <specsDir>. Report, per tutorial: recorded vs spec-only,
recordedAt vs spec mtime (stale?), and any missing artifacts (no MP4 / no PNGs / no catalog entry).
Output a tight table. Never start a recording in this mode.
Principles
- Two approval gates are mandatory โ scenario, then tutorial. They are the whole point.
- done = proven โ show the rendered video / a screenshot; state what passed and what didn't.
- Honesty in narration โ if the UI can't do a step, say so on camera; don't hide it.
- No fabrication โ never claim a render/test passed without the artifact.
- Real video is the headline โ when ffmpeg is available, render the motion MP4 (the app actually
moving + narration). The no-ffmpeg HTML player and the screenshot slideshow are the graceful
fallbacks when ffmpeg or the recorded session video isn't available โ never silently downgrade
without saying so.
Part of GrekAI Skills 4 All ยท MIT-licensed, free to use.
Created by Tzvi Gregory Kaidanov โ Set4u. โญ the repo if it helps you.