record-tutorial skill
Record narrated tutorial videos, demos, and walkthroughs using the Vorec Recorder macOS app and CLI.
- GitHub stars
- 9
- Files
- 2
- Last commit
- Oct 26, 2026
- License
- MIT
- Allowed tools
- —
What does the record-tutorial skill do?
record-tutorial is an agent skill. Record narrated tutorial videos, demos, and walkthroughs using the Vorec Recorder macOS app and CLI.
Summary generated from the skill's SKILL.md.
About the record-tutorial skill
Creating narrated tutorial videos, product demos, and walkthroughs is what this skill enables for developers and content creators using macOS. It automates the process of recording a browser-based flow and transforming it into a polished video with AI voice-overs, zoom effects, and cursor animations. An agent uses this skill by writing a manifest file that describes specific user actions, driving a browser via the Vorec CLI, and then running an analysis command to generate a final editable project.
The workflow relies on the Vorec Recorder desktop app and the @vorec/cli tool to capture high-quality H.264 video. It is designed to handle different environments, such as Shopify Admin mode for embedded apps, Connected mode for local codebases, and Explore mode for discovering third-party websites. To ensure high-quality results, the skill manages browser profiles to avoid interfering with the user's active sessions and uses agent-browser to navigate sites through accessibility trees.
What an agent can do with it
- 1Generate a narrated product demoCreate a professional video walkthrough of a new software feature with AI voice-over and zoom effects.
- 2Record a Shopify app tutorialAutomate the recording of an embedded Shopify application using specialized admin mode handling.
- 3Perform live-site discovery for recordingsNavigate and explore a third-party website to map out the steps needed for a screencast.
Written from the skill's SKILL.md. Every use case is checked against a quote from it.
How to install the record-tutorial skill
Each command copies the skill folder into the client's skills directory. Restart the client or start a new session to load it.Install the record-tutorial skill in Plugin
/plugin marketplace add MustaphaSteph/vorec-plugins /plugin install record-tutorial@vorec-plugins
Install the record-tutorial skill in Claude Code
~/.claude/skills/record-tutorial/SKILL.md
$ npx degit MustaphaSteph/vorec-plugins/skills/record-tutorial ~/.claude/skills/record-tutorialInstall the record-tutorial skill in Claude Code (project)
.claude/skills/record-tutorial/SKILL.md
$ npx degit MustaphaSteph/vorec-plugins/skills/record-tutorial .claude/skills/record-tutorialInstall the record-tutorial skill in Codex
~/.agents/skills/record-tutorial/SKILL.md
$ npx degit MustaphaSteph/vorec-plugins/skills/record-tutorial ~/.agents/skills/record-tutorialInstall the record-tutorial skill in Gemini CLI
~/.gemini/skills/record-tutorial/SKILL.md
$ npx degit MustaphaSteph/vorec-plugins/skills/record-tutorial ~/.gemini/skills/record-tutorialInstall the record-tutorial skill in Claude.ai
npx degit MustaphaSteph/vorec-plugins/skills/record-tutorial record-tutorial && zip -r record-tutorial.zip record-tutorial # claude.ai → Customize → Skills → + → Create skill → Upload a skill → record-tutorial.zip
SKILL.md
View on GitHubRecord Tutorial with Vorec
Read this entire file before recording anything
This skill is split into two halves:
- Workflow (Steps 0 → 10) — what you do, in order, when the user asks for a recording.
- Reference Rules (the appendix at the bottom) — every rule the workflow references, inlined. Topics: agent behavior, recording types, scroll mechanics, pacing, actions, end-state verification, validation, context writing, narration rules + styles, explore mode, live-site discovery, connected mode, Shopify Admin specifics, article-guide parsing, auth, CLI commands, running code, Playwright, troubleshooting.
Read both halves in full at the start of every recording job. Do not skip a Reference Rules section because it "doesn't seem relevant" — you cannot reliably judge relevance until you know what's in it. Past failures have been traced to agents skipping scroll, pacing, and similar sections that turned out to be load-bearing for the specific case.
Safety rules — read these once, follow always
Never pkill Chrome broadly — track what you open and kill only that
Discovery and recording use Chrome/Chromium profiles. If a stale process is holding a profile lock, you may be tempted to clean up. Do not kill all Chrome processes — that wipes the user's actual browsing session, open tabs, and any in-flight work.
The pattern: scoped per-session profile
Every time you launch a browser for discovery (playwright-cli, agent-browser, manual Chromium), use a unique per-session profile path so any later cleanup is automatically scoped to ONLY the windows you opened:
# At session start — declare a unique profile path
SESSION_PROFILE="/tmp/vorec-discovery-$(date +%s)"
# Use it consistently throughout discovery
playwright-cli open https://example.com --profile "$SESSION_PROFILE"
playwright-cli snapshot
playwright-cli click "role=button[name='X']"
# Cleanup at session end — kills ONLY processes pointing at this profile
pkill -f "$SESSION_PROFILE" 2>/dev/null || true
rm -rf "$SESSION_PROFILE"
Wrong vs. right
| Wrong (kills user's browser) | Right (scoped to your session) |
|---|---|
pkill -9 -f "Google Chrome" |
pkill -f "$SESSION_PROFILE" |
pkill chrome |
pkill -f "/tmp/vorec-discovery-..." |
killall "Google Chrome" |
pkill -f "Vorec/Profiles/<slug>" (recording-time profile) |
| "I'll close all Chrome to be safe" | Close ONLY the windows your session spawned |
When you didn't use a scoped profile
If you forgot to launch with --profile $SESSION_PROFILE and now have a hanging Chrome process you'd like to clean up: do nothing automatically. Tell the user verbatim:
I have a stale Chrome process I'd normally clean up, but I didn't open it with an isolated profile so I can't tell it apart from your real browser. Please quit any leftover windows manually.
Asking the user to close windows is annoying once. Killing their entire browser session is unforgivable.
Recording-time cleanup is the CLI's job, not yours
vorec run already kills only the processes pointing at its own recording profile dir (see cleanProfileForLaunch in run.ts). You should not pre-emptively pkill anything before running it. If vorec run errors due to a profile lock, just re-run the command — the CLI handles its own cleanup.
Never delete .vorec/ directories without asking
Each .vorec/<slug>-<timestamp>/ folder is the user's session state — manifest, sidecar, optionally an unsubmitted MP4. Deleting one mid-flow loses the recording. If a directory looks stale, ask first.
Never push or commit on the user's behalf without explicit approval
Showing the user a diff and getting agreement that the change is good is not authorization to commit or push. Only commit or push when the user explicitly says "ship", "push", "commit", or equivalent. Phrases like "ok", "looks good", "agreed", or "X is better" are reactions to analysis, not green lights.
What is Vorec?
Vorec (vorec.ai) turns screen recordings into narrated tutorial videos. You record a flow — Vorec adds AI voice-over, zoom effects, cursor animations, subtitles, and a full video editor.
How recording works
Recording is done by the Vorec Recorder desktop app (macOS only). The app captures the browser window natively (ScreenCaptureKit, 2× retina, H.264) and saves an MP4 locally. The CLI (@vorec/cli) is a driver: it automates the browser and tells the app what to capture. Upload and narration happen later, only after the user approves the local MP4 and you run vorec analyze.
You do not record with Playwright, FFmpeg, or any other tool. Only the app records. If the app is not installed, stop and tell the user to install it — do not suggest alternatives.
Your role as the AI agent
- Verify the app is ready (installed, signed in, permission granted).
- Write a
vorec.jsonmanifest describing the flow (url, viewport, actions). - Run
npx @vorec/cli@latest run vorec.json. The CLI launches Chromium, tells the app to record that window, drives the actions, stops, and writes a local MP4 plus.vorec.jsonsidecar. No upload and no credits yet. - Show the MP4 to the user and wait for explicit approval.
- Run
npx @vorec/cli@latest analyze <mp4>only after approval, then return the editor URL to the user.
Vorec then:
- Reads your tracked actions (descriptions, context, coordinates)
- Writes narration scripts that explain each step
- Places click markers, zoom targets, and cursor effects using your coordinates
- Gives the user an editor URL where they can preview, edit, and export
The better your action tracking (name, description, context), the better Vorec's narration will be. You are the eyes — Vorec is the voice.
Recording benchmarks:
- Short tutorial: 5–15 tracked actions
- Deep walkthrough: 15–30 tracked actions
- Final video sweet spot: 1–3 minutes
- More than 30 actions or 4 minutes → consider splitting into multiple recordings
FIRST: Load agent-behavior rules
Before anything else, read the agent-behavior section below. It's short and teaches you:
- Act first, ask later
- Never batch 3+ questions
- Prefer sensible defaults
- Fix silently, retry without reporting small failures
- End with a link/path, not an essay
These rules override everything else.
Step 0: Detect the mode
Auto-detect — don't ask the user unless you're unsure:
- Project has
shopify.app.tomlOR URL isadmin.shopify.com/...→ Shopify Admin mode (read the shopify-admin section below) - User mentions an external URL (any third-party site — SaaS dashboards, landing pages, competitor products) → Explore mode
- User mentions their own project and you can see the codebase → Connected mode
- Not sure → ask ONE question.
Shopify Admin: embedded apps require special handling — never record from the raw tunnel URL, never automate Google login, use a dedicated browser profile. Connected: you have the source code — read components for selectors, validation, success states. Explore: you don't have the code — discover the page via Playwright snapshots. Read the explore section below.
Step 0.5: Detect the recording type
Read the recording-types section below, then classify: task tutorial / website tour / bug reproduction / UX review.
For external URLs in Explore mode, also read the live-site-discovery section below.
Prerequisites — ALL must pass
Run this single command and read the output:
npx @vorec/cli@latest check
The @latest tag is critical — without it, npx reuses whatever version is in your local cache, which can be months stale and silently produce broken recordings (e.g. cropped-coords bug fixed in 2.25, hidden-input clicks fixed in 2.27, parallel iframe resolution in 2.26). Always pin @latest on the CLI, both for check and for the actual run/analyze commands.
The check verifies:
- Vorec Recorder app is running (macOS only)
- User is signed in to the app
- Screen Recording permission is granted
- cliclick is installed (so the cursor is visible in recordings)
- Vorec account has credits and project slots available
Confirm the CLI version is current
After vorec ... check completes, also run:
npx @vorec/cli@latest --version
Compare the output to the latest published version (the CLI itself prints a warning when stale; in @vorec/cli@2.28.0+ it auto-checks the npm registry and aborts on a major-version gap). If the version is more than one minor behind, force a clean reinstall before proceeding:
npm uninstall -g @vorec/cli # removes any global pin
npm cache clean --force # clears npx cache
npx @vorec/cli@latest --version # verifies fresh fetch
A stale CLI is the #1 source of "I thought we fixed that bug" failures. Always confirm the version before recording.
If the app is NOT installed or not running
Stop and tell the user, verbatim:
The Vorec Recorder app is required to record. Install it from https://vorec.ai/download, open it, sign in, and grant Screen Recording permission — then ask me again.
Do not offer alternatives. Do not fall back to Playwright recordVideo, FFmpeg, screencapture, or any other tool. The app is the only supported recorder.
If cliclick is missing
Run brew install cliclick. Without it, the mouse cursor is not visible in the recording.
Install the discovery browser (agent-browser)
For live-site discovery (Explore mode), the skill uses agent-browser — a CLI that returns a compact accessibility tree with ref tags (@e1, @e2) instead of full DOM dumps. It keeps discovery tokens small and selectors deterministic.
Check + install in one line:
command -v agent-browser >/dev/null 2>&1 || npm install -g agent-browser
agent-browser install # first-time: downloads Chrome. Safe to re-run (no-op after first)
If npm install -g fails due to permissions, fall back to npx agent-browser for every call — slightly slower but no install needed.
API key
The CLI needs a Vorec API key for analysis steps. Save once: npx @vorec/cli@latest init (the skill's rule files cover this — see the auth section below).
Step 1: Elicit URL + discovery mode + goal + audience + gotchas — one message
The user told you what flow to record. You still need to know where to record it, whether you can read their code, why, for whom, and what to watch out for. Without this, your discovery is blind, your narration is generic, and you may record against the wrong URL entirely.
First — detect what URLs are actually available
Before asking, quickly scan the workspace for real URL signals. Do NOT ask about URLs that don't exist. Do NOT invent a "your-live-domain.com" placeholder.
Check, in order:
| Signal | What it tells you |
|---|---|
package.json → scripts.dev / dev:* |
local dev port (usually localhost:3000) |
package.json → homepage field |
deployed URL |
vercel.json, .vercel/project.json |
Vercel-hosted deployed URL |
netlify.toml → [build].publish + netlify project |
Netlify-hosted deployed URL |
wrangler.toml → routes / *.workers.dev |
Cloudflare Workers deployed URL |
shopify.app.toml → application_url |
Shopify embedded app (uses admin.shopify.com host) |
.env, .env.local → NEXT_PUBLIC_*URL, PUBLIC_SITE_URL, VITE_*_URL |
explicit deployed URL |
README.md → first http(s) link in a "Live demo" / "Production" / "Deployed at" section |
deployed URL |
git remote -v → GitHub Pages URL (github.io) |
deployed URL if that's where it lives |
Record what you found — 1 localhost option, 0-1 deployed option, or neither.
Then — ask, with REAL options only
Present URL choices based on what you detected. If the user already pasted a URL in their request, make that the pre-selected option. Never fabricate options.
Got it — I'll record
<what they asked for>.Before I start exploring:
Which URL should I record against?
<list the real options you found, e.g.:>
http://localhost:3000(your local dev server — from package.json dev script)https://example.com(your deployed site — from package.json homepage)- or paste another URL
(If you didn't find any URL at all, just ask: "Which URL should I record? Paste a link.")
Can I read your source code for discovery, or should I stay out of it?
- Read code — faster, more accurate selectors (I stick to the files related to this flow; I don't copy secrets)
- Live only — I explore the page through snapshots, never open your files
(If no code is present in the cwd, skip this question — default to live only.)
What's the goal of this video? (e.g. "show new users how fast signup is", "document how admins manage refunds", "explain feature X to the sales team")
Who's watching? (customer, internal team, developer, investor — shapes tone + what details to show)
Anything I should pay attention to or avoid? (e.g. "don't show pricing because it's changing", "the first-time onboarding popup should be dismissed before recording", "the Save button looks stuck for 2 seconds — that's normal", "use product 'Acme Pro' — it's our demo product")
Reply with those or say "go" for sensible defaults.
Always ask, even when there's only one URL option
If the user only has localhost:3000 detected and no deployed URL, still ask. They might want to paste a totally different URL (a competitor site, a different env, a staging domain). The question costs one line; the wrong URL on camera costs a re-recording.
Why each question matters
- URL → Determines WHERE the recording happens. Local dev shows seed data + dev banners; live prod shows real branding. User's call, not yours.
- Discovery mode → Whether you're allowed to grep the codebase at all. Users may prefer live-only for privacy, to avoid leaking secrets, or because their deployed prod doesn't match current code (stale branch, migrations pending).
- Goal → Determines which path to show when flow has alternatives (fastest signup vs. feature-rich signup), what to highlight, what to gloss over
- Audience → Shapes narration style, which details to name, what terminology level to use
- Gotchas → Catches things you CANNOT discover by exploring: feature flags, flaky UI, specific demo data requirements, first-time-user popups, rate limits, region-specific UI
What the agent does with the answers
- URL answer → this becomes the manifest
url. If the user picked a URL different from what they initially mentioned, that's the one that wins. - Discovery mode answer → controls Step 3. If "live only", you MUST NOT open any local source files even when the cwd has the code. Live dry-run only.
- Goal answer → becomes
videoContextin the manifest (Gemini uses it to ground narration) - Audience answer → influences which narration style to suggest in Step 6
- Gotchas answer → added to discovery checklist; agent explicitly verifies each one during dry-run
If the user says "go" / "defaults"
Proceed with reasonable guesses:
- URL: whatever they initially mentioned; if nothing, the deployed domain inferred from the repo
- Discovery mode: live-only — safer default. Don't read code unless the user says you can.
- Goal: what the flow name implies ("record checkout" → "show how to complete a purchase")
- Audience: generic users
- Gotchas: none known; agent will ask mid-discovery if anything weird shows up
Do NOT skip the question just because it looks obvious. A user who says "record our checkout" might mean localhost, their staging env, or production — you cannot guess which one they want on camera.
If the user shares an article / guide / docs link
When the request includes a link to a help article, documentation page, or any step-by-step guide (Crisp help, Intercom, Notion docs, blog tutorial, etc.) — read the article-guide-parsing section below now. That article is the source of truth for what the video must show: its screenshots define the UI states, its demo values define what to type. Parse them before writing anything.
Signals that trigger this:
- User pastes a URL before the recording request
- Phrases like "record this", "follow this guide", "same as this article", "make a video of this"
- The URL resolves to a help center / docs / blog post
Step 2: Check the page first — don't assume login
Before discovery, find out whether the target URL is public, auth-walled, or partially gated. This shapes the entire rest of the flow.
playwright-cli open <URL>
playwright-cli --raw snapshot
Look at the snapshot:
- Public page, target content visible → no login needed. Go to Step 3.
- Login page / redirect to auth → login required. Open in headed mode so the user can sign in, capture the session. Read the auth section below.
- Partially visible, some actions need auth → ask the user one question: "Do I need to log in to do
<specific action>?"
NEVER assume login. Most public sites (marketing, docs, tools) need none. Only handle auth when you SEE a login wall or the user tells you.
Step 3: MANDATORY deep discovery — DO NOT SKIP, DO NOT CUT CORNERS
You MUST discover the full flow BEFORE writing a single line of manifest. Not optional. Discovery is where recordings are won or lost.
Discovery has two phases — a high-level exploration pass and a selector-verification pass. Skipping either produces broken recordings.
Phase 3a — Flow exploration (what exists, where, what's the UX)
This is the "walk the site and map it" phase. You produce a flow map that lists:
- Every URL in the sequence (including redirects)
- Every step / page / modal / popup encountered
- Field inventory per page (textbox names, button labels, constraints)
- Pre-filled values, defaults, validation errors
- Minimum player counts / field requirements / enable-disable triggers
- Success state (end URL, visible text, success banner)
Default discovery tool: agent-browser (installed in prereqs). It returns a compact accessibility tree with ref tags like @e1 instead of full DOM dumps — keeps the agent's context small and selectors deterministic.
| Tool | When to use |
|---|---|
agent-browser |
Default for all live-site discovery. Produces a compact a11y tree with refs, URL transitions, and element-at-ref lookups. Low token cost. |
playwright-cli snapshot + click loops |
Used in Phase 3b (selector verification) where you need the full ARIA snapshot with role + name for every target element. |
| Direct source-code reading (Connected mode with user permission) | When user allowed "read code" in Step 1 and the flow is static enough that code tells the full story. |
Standard pattern: agent-browser for the high-level site map (Phase 3a), then playwright-cli snapshot per element (Phase 3b).
Phase 3b — Playwright selector verification (MANDATORY no matter which tool Phase 3a used)
This is the part that catches the #1 failure mode: the Playwright selector isn't what the high-level tool showed.
For EVERY action in your planned manifest, you must use playwright-cli --raw snapshot to confirm the element's ARIA role and accessible name. A site-mapping tool may describe an element only by its visible label — e.g. the doc calls something a "tab" but doesn't specify whether that's a role="tab", a role="button", or a plain link styled like a tab. If you guess wrong and write button:has-text('Label') when the element is actually role="tab", Playwright will fail to find it.
For each action:
- Navigate to the page where the action happens (
playwright-cli open+ clicks to reach it). playwright-cli --raw snapshot— find the target element.- Record its
role+ accessiblenameas they appear in the snapshot:- <role> "<name>" [ref=eNN] ↑ role ↑ name - The manifest selector becomes
role=<role>[name='<name>']. Use that EXACT Playwright syntax — not CSS, not:has-text()guesses. - Verify the selector resolves by actually clicking it via
playwright-cli click <ref>and snapshotting the result. - Note observed response time for the manifest's
pausevalue. - Append an entry to
discovery_log.json(see below) — this is the CLI-enforced proof that you walked this action.
This phase is non-negotiable. Whatever Phase 3a told you is the flow, Phase 3b confirms the Playwright selectors that will actually fire during recording.
Click interception: when a "correct" selector still won't click
This is the Phase 3b failure mode that snapshots can't catch on their own. An ARIA snapshot shows role=checkbox[name='Foo'] is present — but the click doesn't toggle anything. Recording then hangs ~10s per intercepted click and the run aborts with a Playwright actionability error.
It happens when a design system hides the real input behind a styled wrapper. Polaris (Shopify Admin), Material UI, Radix, Mantine, Headless UI — all do some variant of:
<label class="Polaris-Checkbox">
<input type="checkbox" class="visually-hidden"> ← real input, opacity:0, 1px×1px
<span class="Polaris-Checkbox__Backdrop"> ← visible "checkbox", catches clicks
</label>
Playwright's actionability check sees the input as display:none-equivalent and refuses. Two ways to fix it — prefer the first:
1. Wrapper-selector first (preferred — purer, no CLI flag). Find the visible parent and target it instead. For Polaris:
role=checkbox[name='Select: Example 1 & 2'] ← intercepted
[aria-label='Select: Example 1 & 2'] ← works (the visible label)
For Polaris listbox options:
role=option[name='India'] ← may intercept
.Polaris-Listbox-TextOption:has-text('India') ← works
Phase 3b discovers these by clicking the role= variant first, watching it fail to change UI, then re-snapshotting around the element to find the wrapping [aria-label=…] or class-based target.
2. "force": true on the action (fallback — when wrappers aren't clean).
Add "force": true to the action in vorec.json. The CLI passes it to Playwright's click and skips actionability checks — the click dispatches at the element's coordinates regardless of overlay. The framework's JS handler still picks it up.
{
"type": "click",
"selector": "role=checkbox[name='Apply this rate for certain countries only']",
"force": true,
"description": "Toggle countries-only checkbox"
}
Use force ONLY when (a) Phase 3b verified the selector is correct AND (b) the click still intercepts. Never as a workaround for a wrong selector — force-clicking the wrong element produces wrong UI state silently. Available in @vorec/cli@2.27.0+.
How to tell during Phase 3b which path you need:
- Click the role= selector via playwright-cli/agent-browser
- Snapshot the page
- If UI changed → role= selector works, no force needed → proceed.
- If UI did NOT change → check for a wrapper attribute (
[aria-label=…],[data-…]) or a stable class on the parent (.Polaris-Listbox-TextOption). Use that. Try again. If still no change, fall back to"force": trueon the role= selector.
Files in this skill
2record-tutorial skill questions
How do I install the record-tutorial skill in Claude Code?
Run npx degit MustaphaSteph/vorec-plugins/skills/record-tutorial ~/.claude/skills/record-tutorial. Claude Code loads skills from ~/.claude/skills (all projects) or .claude/skills (one project) and uses a skill when its description matches the task.
Which clients can use the record-tutorial skill?
Any client that reads the Agent Skills format: Claude Code, Codex, Gemini CLI and claude.ai (upload as a ZIP). Scripts in the skill run only where the client allows code execution.
What tools can I use to record the video?
You must use the Vorec Recorder desktop app (macOS only). Do not attempt to use Playwright, FFmpeg, or other tools as they are not supported.
How do I ensure the mouse cursor is visible in my recording?
You need to have 'cliclick' installed on your system. If it is missing, you can install it using 'brew install cliclick'.
Can I record on Windows or Linux?
No, the Vorec Recorder desktop app is only available for macOS.
What should I do if the CLI version is outdated?
You should always use the @latest tag with npx. If the version is more than one minor version behind, perform a clean reinstall using npm uninstall and npm cache clean.