Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Video Lesson

ASecurity

Make a narrated lesson video about lpm from the real desktop app, recorded on a pristine data directory. Title and optional narration text in, MP4 with OpenAI voice out, audio in sync with the clicks. Use when the user asks for a video lesson, tutorial, screencast, or YouTube video about lpm.

150 stars
0 votes
0 copies
0 views
Added 9/20/2026
developmentjavascriptrustgojavanodegitfrontendsecurity

Works with

claude codecursorterminalcli

Security Analysis

A100/100

Scanned 9/20/2026

Install to Claude Code

$npx -y skills add gug007/lpm --skill video-lesson --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Video Lesson?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Video Lesson
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/gug007-video-lesson/badge)](https://www.skillsdirectory.com/skills/gug007-video-lesson)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
name: video-lesson
version: 3.0.0
argument-hint: "\"<title>\" [-- <text>]"
description: "Make a narrated lesson video about lpm from the real desktop app, recorded on a pristine data directory. Title and optional narration text in, MP4 with OpenAI voice out, audio in sync with the clicks. Use when the user asks for a video lesson, tutorial, screencast, or YouTube video about lpm."
---

Generate video tutorial from title and optional narration text.

- no YAML, config files, or CLI unless the title is about them.
- use OpenAI key in the Keychain (`security add-generic-password -s lpm-video -a openai -U -w`)
- generate audio first to sync with the video.
- record the real **desktop app** (`desktop/frontend`, the `tauri dev` debug build at `src-tauri/target/debug/lpm-desktop`, UI from Vite on :9245 — started if it is not up). The app runs on its own data directory, `~/.lpm-lessons` (`LPM_DIR`), wiped before every take so each lesson opens the way a fresh install does; the user's real `~/.lpm` is never written (only its last Claude usage reading is copied in, see below) (`--lpm-dir <dir>` to use another directory, `--keep-state` to keep the previous take's state). Demo project folders live in `/Users/Shared/lpm-lessons` (`LPM_LESSON_WORKSPACE`), a path with no user name in it, wiped with the state.
- pipeline: `node scripts/make.js <slug>` reads `lesson.json` + `beats.js` from `~/Movies/lpm-lessons/<slug>/` and writes the MP4 there (`--no-audio --frames` = dry run with JPEG frames; `--mux-only` re-composes the last take; `--variant name --voice marin --style "…"` renders a voice variant into `variants/`; beats land clicks on spoken words via `cue`). `lesson.json` `"source": "demo"` (or `--demo`) records the website demo at http://localhost:3000/demo in headless Chromium instead.
- the app is driven through its lesson control socket (`lesson.rs`, debug builds only, `LPM_LESSON_SOCKET`): JavaScript runs in the main webview, the window is sized to the frame and centred on the main display, always on top, and captured by ffmpeg (AVFoundation, Screen Recording permission for the terminal). Clicks and typing use the real pointer and keyboard through `cliclick` (Accessibility permission) so hover states and native sheets work — do not touch the mouse or keyboard during a take; `--dom-mouse` dispatches events in the page instead. The pointer is put back where it was afterwards.
- beats: `s.moveTo/click(sel, { at, ms, cue })`, `s.type(text)`, `s.press("Enter")`, `s.keys("cmd+shift+g")` (native shortcut, for the folder-picker sheet), `s.hideCursor()/showCursor()`, `s.waitFor(sel)`, `s.hold(ms)`, `s.holdUntil(ms)`, `s.card(title, { hold, until })` (`until: "<cue>"` ends the card on that spoken word so the rest of the line plays over the app), `s.zoom(sel, { scale, ms, at, cue })` / `s.zoomOut({ ms, cue })`.
- zoom: when the narration is about a small control (a button, a sidebar row, a form), push the picture in on it with `s.zoom(sel, { scale: 1.6–2, ms: 700–900, cue })` right before the pointer moves there, and ease back with `s.zoomOut()` once the next thing to see is bigger (a dialog opening) or the line moves on. The zoom is applied at mux time (`zoompan` in `scripts/compose.js`) from keyframes on the timeline, easing over `ms` and finishing on the cue word; cards stay unzoomed on top. Keep it to a few per lesson. Selectors: CSS, `text=<substring>`, `css:has-text("…")`, and `a >> b` chains; matches must be visible. `module.exports.setup = async ({ lpmDir, workspace, lesson, settings })` runs before launch to seed folders and patch `settings.json` through `settings({ … })` (for example `defaultProjectDirectory`). A seeded folder needs a manifest the app can read — a `package.json` with a `dev`/`start` script, a Procfile, `manage.py`… — or adding it writes the `configure me` placeholder instead of detected services (lesson 02 seeds a dependency-free Node server per folder, runnable with `npm run dev`). The sidebar meters are seeded from the real app's last Claude reading (`~/.lpm/agent-limits.json`, read only) with the meter enabled; `"limits": false` in `lesson.json` leaves them out. The app's "Local Folder" opens the native open panel as a sheet inside the window: drive it with `s.keys("cmd+shift+g")`, `s.type(path)`, `s.keys("return")`, type-ahead a folder name, `s.keys("return")`.
- agents in a lesson: the seeded header actions are `[data-actions-zone="header"] >> button:has-text("Claude")` / `…("Codex")`; a click opens the agent in its own tab and Claude's prompt is ready within a second. The composer is open on a fresh install: type into `[data-composer-box] >> [role="textbox"]` and click `[data-composer-box] >> button[aria-label="Send"]` (a Send click reads better on video than a key). Wait for the reply with `s.waitForAgentReply(projectRoot, { since })` — it watches Claude's transcript, so the "and Claude answers" line starts with the answer on screen; the log says `agent replied` or `no agent reply` (that is the pass/fail of the take). Claude runs with the user's real login: the plan line, statusline, cost and effort label show on screen. A project folder needs Claude's one-time folder trust in `~/.claude.json` (`/Users/Shared/lpm-lessons/Projects/client-portal` and `spoon-knife` are trusted; for a new folder name, run `claude` there once and accept, or the first launch shows the trust prompt).
- keys: `s.press("Enter")` and `s.keys("return")` both go through System Events; a cliclick key press (`kp:`) never reaches the page. `s.type` (cliclick `t:`) works.
- a take may be started from inside a Claude Code session: `app.js` strips that session's `CLAUDE_CODE_*` / `CLAUDECODE` markers from the app's environment (inherited, the recorded Claude runs as a child session with transcript saving off) and asks a lesson app left on the socket to quit before launching.
- re-rendering a published lesson: copy the old MP4 aside first (the mux overwrites `<slug>.mp4`); a full take is ~5 minutes (audio → record → cards → mux), so review `frames/NN-<beat>.jpg` from `--frames` before watching the MP4. Kill nothing mid-take: the app, the capture and the pointer are put back by the script itself.
- what the recording shows is the real machine: the open panel's sidebar lists the user's own Favorites and home folder name, and the sidebar meters show real Claude/Codex usage — check frames before publishing. A "Clone Repository" beat performs a real `git clone`; use a small public repo.
- audio should be synced with the video.
- audio should be natural, not robotic: voice `marin` with the `DEFAULT_STYLE` prompt in `scripts/make.js` (casual over-the-shoulder walkthrough, every word crisp and easy to catch; user's wording 2026-09-19); `lesson.json` `voice`/`style` or `--voice`/`--style` override per lesson. A lesson's already-spoken clips survive a style change: the cache keeps a clip whose model, voice and text match even when the style prompt differs (log line `keeping the clip spoken with the previous style`), because a re-spoken line changes length and desyncs the recorded take; `--respeak` re-speaks every line and then needs a new take. Hear a style before adopting it: `variants/style-old.m4a` and `style-new.m4a` in lesson 02 are four lines spoken each way.
- frame: the app window floats centered on a warm off-white canvas (`#f5f4f0`), ~82% of the width, rounded corners and a soft shadow, no full-bleed (`FRAME` in `scripts/stage.js`; for app takes the frame is composited at mux time by `scripts/compose.js` from the raw window capture).
- topic cards: when the lesson changes topic, show a title card first — big serif title on a warm canvas (`#ebe5d9`) with three pale pools of peach, sand and sage drifting slowly behind the words, nothing else; the words animate in one after another (rise + un-blur), the card fades out — via `s.card("Title")` in the beat, spoken over by that line's narration (app takes render the cards as clips in `cards/` and overlay them at mux time).
- open and close on cards: the recording starts on the card canvas (no app flash) with the first beat an `s.card("<lesson title>")`; the last narration line is silent (`{ "id": "outro", "ms": 3200 }`) and its beat is `s.card("lpm.cx", { hold: true })` — the website URL held to the end.
- background music: a soft royalty-free bed (`~/Movies/lpm-lessons/_music/bed.mp3`, Mixkit free licence, see LICENSE.txt there) mixed 14 LU under the narration, ducked further while lines are spoken, fading in over the title card and out over the end card; `--no-music`, `--music <file>` or `music: false` in `lesson.json` to change it.

Attribution

gug007gug007
View sourceMore from gug007 →
SSkills DirectorySkills Directory

Know which skills are safe — weekly.

Best new skills + every skill we flagged as malicious. From the team that scanned 103,619.

Join free

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Know which skills are safe — weekly.

Best new skills + every skill we flagged as malicious. From the team that scanned 103,619.

Join free

Related Skills

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

281612 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2132 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

9881 votes

Pentest

PTES-aligned adversarial security audit for backend, frontend, and mobile applications. Produces a CVSS-scored Hacker Report with verified PoCs and phased remediation.

5491 votes
View all in development →