Lesson File Format

Reference for writing custom lesson courses for Pianove.

Directory Layout

pianove/lessons/          ← built-in lessons, read-only, versioned with the app
~/.pianove/packages/      ← user-installed packages (lessons & courses)

A .pianove-pkg file is a renamed .zip of a lesson or course folder. It can be imported via the in-app package manager or the file picker.

Lesson Bundle

Each lesson lives in its own folder:

lessons/welcome/
  meta.json          ← identity, authorship, difficulty, tags
  en.json            ← localized strings (title, descriptions, hints)
  de.json            ← additional locale files follow the same pattern
  steps.json         ← ordered list of step blocks
  assets/
    notation_1.xml   ← MusicXML snippets rendered by PyLute
    audio_1.ogg      ← optional backing audio

meta.json

{
  "id": "welcome",
  "version": "1.0.0",
  "author": "Pianove",
  "difficulty": "beginner",
  "tags": ["intro", "basics"],
  "locales": ["en", "de"],
  "estimated_minutes": 5
}

steps.json

A step is a typed block. The renderer dispatches on type:

[
  {
    "type": "text",
    "content_key": "step1_text"
  },
  {
    "type": "notation",
    "file": "assets/notation_1.xml",
    "caption_key": "step1_caption"
  },
  {
    "type": "exercise",
    "notes": ["C4", "E4", "G4"],
    "caption_key": "step1_exercise"
  },
  {
    "type": "quiz",
    "question_key": "step1_question",
    "options_keys": ["opt_a", "opt_b", "opt_c"],
    "correct": 0
  }
]

content_key, caption_key, etc. are looked up in the locale file for the active language, falling back to en.json.

Step Types

TypeDescription
textExplanatory prose, supports inline bold/italic via simple markup
notationSheet music rendered by PyLute from a MusicXML asset file
exerciseInteractive play-along — user must play specified notes on MIDI keyboard
quizMultiple-choice question with immediate feedback

Course Bundle

A course is an ordered collection of lessons:

courses/beginner_path/
  meta.json          ← course identity and lesson order
  en.json
  de.json
{
  "id": "beginner_path",
  "version": "1.0.0",
  "author": "Pianove",
  "difficulty": "beginner",
  "lessons": [
    "welcome",
    "c_major_scale",
    "reading_notes",
    "first_melody"
  ]
}

Lessons referenced here can be bundled inside the course zip or declared as dependencies resolved from already-installed packages.

Package Manager

Import source: local file picker (.pianove-pkg zip) — v1. Future versions may support a registry index at a hosted index.json.

Package Resolution Order

  1. Built-in (pianove/lessons/, pianove/courses/)
  2. User-installed (~/.pianove/packages/)
  3. User-installed packages shadow built-ins of the same id — allows community patches

Design Principles

  • Human-readable — JSON + MusicXML are plain text, readable, diffable, and Git-friendly
  • Localizable — every user-facing string lives in locale files, following the same pattern as the rest of the app
  • Forkable — anyone can copy a lesson folder, edit it, and share the zip or submit a PR
  • Extensible — new step types can be added without breaking existing lessons; unknown types are skipped with a fallback UI