Port Igniter
Get Started

Lesson Files

The lesson file format and the exact shape of every block type, from text and code to video, audio, downloads, embeds, and lab steps.

LMS Support Home

Each lesson lives in items/<lesson-id>.lesson.json.

{
  "schema_version": 1,
  "id": "what-is-git",
  "type": "lesson",
  "completion": { "mode": "manual" },
  "duration_min": 8,
  "objectives": ["o1"],
  "blocks": [ ]
}
Field Required Rules
schema_version Yes 1.
id Yes Matches the file name and the item ID in course.json.
type Yes "lesson".
completion.mode No manual (default), on_view, video (needs an upload or url video block), or steps (needs a Steps block).
duration_min No 0 to 10,000, or null. Added up into the course length.
objectives No Objective IDs, each defined in course.json.
blocks Yes An ordered list of up to 300 blocks.

Each block is { "id": "<local id>", "type": "<type>", ... }, and block IDs are unique within the lesson. Fields not listed for a type are rejected. The lesson’s title comes from course.json and is shown as the page heading, so start Markdown headings at ##.

Block types

text

markdown is required.

{ "id": "intro", "type": "text", "markdown": "## Heading\n\nParagraph with **bold** and `code`." }

callout

kind (note, tip, important, warning, or caution) and markdown are required. title is optional, up to 80 characters.

{ "id": "tip1", "type": "callout", "kind": "tip", "title": "Think in snapshots", "markdown": "Short, one idea." }

code

code is required, up to 50,000 characters. Optional: language in lowercase (such as bash, python, js, php, json, sql, yaml, html, or css), filename (up to 120 characters), highlight_lines (line numbers starting at 1), and show_copy.

{ "id": "run", "type": "code", "language": "bash", "filename": "terminal", "code": "git init\ngit status", "highlight_lines": [1], "show_copy": true }

image

src (an assets/ path in the zip) and alt (1 to 300 characters describing what the image shows) are required. Optional: caption (up to 300 characters) and zoomable.

{ "id": "diagram", "type": "image", "src": "assets/branch-diagram.png", "alt": "Four commits on main with a feature branch after the second", "caption": "Branching." }

video

provider and src are required.

provider src
youtube The video ID or a full YouTube link.
vimeo The numeric ID or a Vimeo link.
url A direct https:// link to an .mp4 or .webm file.
upload An assets/ path to an .mp4 or .webm file in the zip.

Optional: title (up to 200 characters), poster (an assets path), captions, transcript_md, and complete_at_percent (1 to 100, default 90: how much must actually be played to count as watched). captions is a list of { "lang": "en", "label": "English", "src": "assets/intro.en.vtt" }.

{ "id": "vid", "type": "video", "provider": "youtube", "src": "dQw4w9WgXcQ", "title": "Intro", "transcript_md": "Full transcript..." }

Only upload and url videos can be tracked. A lesson whose only video is on YouTube or Vimeo should use "completion": { "mode": "manual" }.

audio

provider (upload or url) and src are required. Uploads are .mp3, .m4a, .ogg, or .wav assets, and URLs are direct https:// links to one. Optional: title and transcript_md. Always include a transcript.

{ "id": "interview", "type": "audio", "provider": "upload", "src": "assets/interview.mp3", "title": "Interview with the maintainer", "transcript_md": "Full transcript..." }

download

files is required: 1 to 30 of { "src": "assets/...", "label": "...", "description": "..." }. label is 1 to 120 characters, and the optional description belongs to each file, up to 300 characters.

{ "id": "sheet", "type": "download", "files": [ { "src": "assets/cheat-sheet.pdf", "label": "Cheat sheet" } ] }

embed

url is required. title and caption are optional. YouTube and Vimeo links become players, and any other link becomes a link card.

{ "id": "more", "type": "embed", "url": "https://git-scm.com/book", "title": "Pro Git book", "caption": "Free online." }

steps

A hands-on lab checklist. steps is required: one or more of { "id", "text_md" }, each with an optional command (shown with a copy button) and output (the expected result, collapsed). title is optional.

{ "id": "lab", "type": "steps", "title": "Lab steps", "steps": [
  { "id": "pull", "text_md": "Download the image.", "command": "docker pull nginx:stable", "output": "Status: Downloaded newer image" },
  { "id": "check", "text_md": "Open <http://localhost:8080> and confirm the welcome page." } ] }

Learners’ ticks are saved per step ID, so keep step IDs stable. Renaming one clears that tick for everyone. Use "completion": { "mode": "steps" } to complete the lesson when every step is ticked.

Markdown

Text, callouts, transcripts, question stems, and explanations use CommonMark with GitHub extensions: tables, task lists, strikethrough, autolinks, and fenced code blocks.

  • Link to your own files by asset path: ![Alt text](assets/diagram.png) or [Download](assets/sheet.pdf).
  • Other links must use http, https, or mailto.
  • Raw HTML is sanitized. Only harmless elements, such as <details>, <summary>, and tables, survive. Scripts, iframes, inline styles, event handlers, and javascript: links are removed.

Assets

Everything a lesson references must be in assets/, and must genuinely be the type its extension claims.

Type Extensions Largest file
Images png, jpg, jpeg, webp, gif (no SVG) 5 MB
Video mp4, webm 500 MB
Audio mp3, m4a, ogg, wav 200 MB
Captions vtt 1 MB
Documents pdf, zip 50 MB
Text txt, md, csv 5 MB

File names can use letters, digits, ., _, and -, up to 200 characters. Lowercase kebab-case is easiest. Unused assets are harmless, but a missing referenced asset fails publishing.

Top