
Tutorial Updates
Orchestrate multi-component tutorials from .manifest.yaml with tape, Playwright, and static assets into combined GIF outputs.
Install
npx skills add https://github.com/athola/claude-night-market --skill tutorial-updatesWhat is this skill?
- Full .manifest.yaml schema: name, title, components, and optional combine rules
- Component types: tape (VHS terminal), playwright (browser capture), and static assets
- Combine layouts: vertical, horizontal, sequential, grid, and picture-in-picture
- Pre-run requires hooks for commands such as npm run serve on Playwright components
- Manifest-driven output paths for per-component and combined GIF generation
Adoption & trust: 1 installs on skills.sh; 304 GitHub stars; 2/3 security scanners passed (skills.sh audits); trending (+100% hot-view momentum).
Recommended Skills
Journey fit
Docs is the canonical first shelf because manifest parsing and tutorial composition are primarily about producing and updating teaching artifacts during product build. The skill defines schemas, component types, and combine layouts for tutorial media—not application runtime backend code.
Common Questions / FAQ
Is Tutorial Updates safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Tutorial Updates
# Manifest Parsing Module Parse `.manifest.yaml` files and tape file annotations for tutorial orchestration. ## Manifest Schema Tutorial manifests define multi-component tutorials with composition rules: ```yaml # Full manifest schema name: string # Required: identifier for the tutorial title: string # Optional: human-readable title description: string # Optional: brief description components: # Required: list of media components - type: tape # Component type: tape, playwright, static source: path/to.tape # Path to source file (relative to manifest) output: path/to.gif # Path for generated output options: # Optional: component-specific options fps: 10 width: 800 - type: playwright source: browser/spec.ts output: assets/gifs/browser.gif requires: # Optional: commands to run before - "npm run serve" - type: static # Pre-existing asset (no generation) source: existing.gif output: existing.gif combine: # Optional: composition rules output: combined.gif # Path for combined output layout: vertical # Layout: vertical, horizontal, sequential, grid, pip options: padding: 10 background: "#1a1a2e" ``` ## Component Types ### Tape Components VHS tape files for terminal recordings: ```yaml - type: tape source: quickstart.tape output: assets/gifs/quickstart.gif options: # Override tape file settings if needed width: 1000 height: 500 ``` ### Playwright Components Browser automation specs: ```yaml - type: playwright source: browser/mcp-dashboard.spec.ts output: assets/gifs/mcp-browser.gif requires: - "skrills serve" options: fps: 12 width: 1280 ``` The `requires` array specifies commands to run before the spec. These run as background processes and are terminated after recording. ### Static Components Pre-existing assets that don't need generation: ```yaml - type: static source: diagrams/architecture.gif output: diagrams/architecture.gif ``` ## Parsing Tape File Annotations Tape files contain inline annotations for documentation generation: ### Annotation Format ```tape # @title: Tutorial Title # @description: Brief description for README # @step Step Name # @docs-brief Concise text for project docs # @book-detail Extended explanation for technical book Type "command" Enter ``` ### Annotation Types | Annotation | Scope | Purpose | |------------|-------|---------| | `@title` | File | Tutorial title | | `@description` | File | Brief description | | `@step` | Block | Step heading | | `@docs-brief` | Block | Concise docs text | | `@book-detail` | Block | Extended book text | ### Parsing Algorithm ```python def parse_tape_annotations(tape_content: str) -> dict: """Parse tape file for documentation annotations.""" result = { "title": None, "description": None, "steps": [] } current_step = None for line in tape_content.splitlines(): line = line.strip() # File-level annotations if line.startswith("# @title:"): result["title"] = line.split(":", 1)[1].strip() elif line.startswith("# @description:"): result["description"] = line.split(":", 1)[1].strip() # Step-level annotations elif line.startswith("# @step"): # Save previous step if current_step: result["steps"].append(current_step) # Start new step step_name = line.replace("# @step", "").strip() current_step = { "name": step_name, "docs_brief": None, "book_detail": None, "commands": [] } elif line.startswith("# @docs-brief"): if current_step: current_step["docs_brief"] = line.replace("# @docs-brief", "").strip() elif line.startswith("# @