Workout-Schema

Zuletzt aktualisiert: 2026-05-29

Your Trainer ist eine Indoor-Cycling-App für mehrere Fahrer auf Android-Tablets. Smart-Trainer-Steuerung mit lokalen Daten + lokaler Kontrolle. Einmalkauf.

Die .ytw-Workout-Datei ist reines JSON — schreibe sie in einem beliebigen Texteditor, importiere sie über das Teilen-Menü und teile sie mit Freunden. Der visuelle Editor deckt die gängigen Fälle ab; das Schema ist der Notausgang, wenn du volle Kontrolle brauchst.

Wann selbst schreiben

Die meisten Fahrer brauchen diese Seite nie — der visuelle Workout-Editor und der AI Workout Coach decken alles ab, von einer 4×8-Schwellen-Einheit bis zu einem Mikroburst-Stack. Greif zum Schema, wenn:

Minimalbeispiel

Die kürzeste gültige .ytw-Datei ist ein Programm mit einem Intervall. Speichere sie mit der Endung .ytw und teile sie in Your Trainer hinein.

{
  "programId": "my-sweet-spot",
  "programName": "My Sweet Spot 30",
  "description": "A short sweet-spot workout.",
  "totalDuration": 1800,
  "workoutType": "POWER",
  "primaryLocale": "en",
  "intervals": [
    { "id": "warmup",   "duration": 300,  "targetPowerPercent": 50, "intensityZone": "Z1", "label": "Warmup",     "intervalType": "WARMUP"   },
    { "id": "work",     "duration": 1200, "targetPowerPercent": 88, "intensityZone": "Z3", "label": "Sweet Spot", "intervalType": "INTERVAL" },
    { "id": "cooldown", "duration": 300,  "targetPowerPercent": 50, "intensityZone": "Z1", "label": "Cooldown",   "intervalType": "COOLDOWN" }
  ]
}

Felder auf oberster Ebene

Das Objekt auf oberster Ebene beschreibt ein Workout-Programm. Pflichtfelder sind markiert.

FeldTypBeschreibung
programId erforderlichstringStabile Kennung. Verwende kebab-case (my-sweet-spot). Der eindeutige Schlüssel für das Workout in deiner Bibliothek — beim erneuten Import einer Datei mit derselben programId wird der vorhandene Eintrag aktualisiert, statt ein Duplikat anzulegen.
programName erforderlichstringAnzeigename in der primären Sprache des Fahrers.
description erforderlichstringEin- oder zweisätzige Beschreibung, die auf der Workout-Karte angezeigt wird.
totalDuration erforderlichinteger (Sekunden)Gesamtlänge des Workouts. Die App berechnet diesen Wert beim Speichern aus den Intervallen neu, daher darf er beim Authoring ruhig inkonsistent sein.
intervals erforderlicharrayGeordnete Liste von Intervall-Objekten oder Wiederholungsgruppen.
workoutTypestringWorkout-Familie: POWER (Standard), HR_ZONE oder ROUTE. Siehe Workout-Typen.
variantstringUntertyp innerhalb der Familie: STANDARD (Standard) oder RAMP_TEST.
primaryLocalestring (BCP-47)Sprache, in der die Strings verfasst wurden. Standard "en". Steuert die sprachübergreifende Fallback-Kette.
categorystringFreie Text-Kategorisierung (z. B. "threshold", "endurance"). Optional.
difficultyinteger (1–5)Subjektiver Schwierigkeitsgrad. Wird auf der Workout-Karte angezeigt.
isUserCreatedbooleanTrue für Workouts, die der Fahrer in der App selbst erstellt hat; false für importierte oder mitgelieferte Workouts. Standard false.
isFavoritebooleanFlag „oben angeheftet“. Fahrer schalten das in der App um; in geteilten Dateien meist weggelassen.
routeProfilearray von { distanceMeters, elevationMeters }Vollständiges Höhenprofil für ROUTE-Workouts. Null für POWER und HR_ZONE.
stringsobject (Sprache → LocaleStrings)Sprachspezifische Übersetzungen von Name, Beschreibung, Intervall-Labels und Hinweisen.

Intervall-Felder

Jedes Intervall-Objekt beschreibt einen Block des Workouts. Die Form des Blocks hängt vom workoutType des übergeordneten Programms ab — Power-Blöcke verwenden Leistungsprozente, HF-Zonen-Blöcke verwenden eine Zonen-Vorgabe.

FeldTypBeschreibung
duration erforderlichinteger (Sekunden)Blocklänge in Sekunden.
targetPowerPercent power-erforderlichinteger (% der FTP)Leistungs-Vorgabe für POWER-Workouts. Schließt sich mit targetHrZone gegenseitig aus.
targetPowerEndPercentinteger (% der FTP)Optionale Endleistung einer Rampe. Wenn gesetzt, interpoliert die Soll-Wattzahl linear von targetPowerPercenttargetPowerEndPercent über den Block.
targetHrZone hr-erforderlichinteger (1–5)HF-Zone für HR_ZONE-Workouts. Schließt sich mit targetPowerPercent gegenseitig aus.
intensityZone erforderlichstringVisuelles Zonen-Token: Z1Z5. Steuert die Farbe in der Terrain-Visualisierung. Siehe Trainingszonen.
intervalTypestringWARMUP, COOLDOWN oder INTERVAL (Standard). Aufwärm- und Auslauf-Blöcke werden aus den reinen Arbeits-Zusammenfassungen ausgeschlossen (durchschnittliche Leistung der Arbeitsblöcke, Time-in-Zone für den Arbeitsteil etc.).
label erforderlichstringAnzeigetext auf dem Block in der primären Sprache des Fahrers. Sprachübergreifende Varianten stehen in strings.<locale>.labels.
idstringStabiler Slug — der Schlüssel, der in strings.<locale>.labels und beim Zusammensetzen von Cue-Schlüsseln verwendet wird. Empfohlen für jedes Workout, das mit Übersetzungen ausgeliefert wird.
autoLabelbooleanTrue, wenn das Label von einem Editor-Preset erzeugt wurde, statt vom Fahrer getippt zu sein. Auto-Labels werden von Your Trainer selbst lokalisiert und benötigen keine sprachspezifischen Einträge in strings. Standard false.
cadenceTargetinteger (RPM)Optionale Trittfrequenz-Vorgabe für den Block (z. B. 60 für Kletter-Übungen mit niedriger Trittfrequenz, 100 für Spin-up-Drills).
cuesarray von CoachingCueCoaching-Hinweise, die während des Blocks ausgelöst werden.

Coaching-Hinweise

Ein Coaching-Hinweis ist ein kurzes Text-Overlay, das während der Fahrt im Cockpit erscheint. Jeder Hinweis hat einen Versatz innerhalb seines übergeordneten Intervalls, den anzuzeigenden Text und eine Dauer, wie lange er sichtbar bleibt.

FeldTypBeschreibung
offsetSec erforderlichinteger (Sekunden)Sekunden ab Beginn des übergeordneten Intervalls, bei denen der Hinweis ausgelöst wird.
text erforderlichstringHinweis-Text in der primären Sprache des Workouts. Sprachübergreifende Varianten stehen in strings.<locale>.cues, indiziert nach <intervalId>:<cueIndex>.
durationSecinteger (Sekunden)Wie lange der Hinweis auf dem Bildschirm bleibt. Standard 5.

Beispiel-Intervall mit drei Hinweisen (die Schlüssel-Zusammensetzung verwendet die id des übergeordneten Intervalls + den Index des Hinweises im Array):

{
  "id": "work",
  "duration": 600,
  "targetPowerPercent": 95,
  "intensityZone": "Z4",
  "label": "Threshold",
  "intervalType": "INTERVAL",
  "cues": [
    { "offsetSec": 0,   "text": "Settle in — find your rhythm." },
    { "offsetSec": 300, "text": "Halfway. Stay smooth.",  "durationSec": 8 },
    { "offsetSec": 540, "text": "One minute. Hold form." }
  ]
}

Lokalisierte Strings & Fallback-Kette

Der strings-Block enthält sprachspezifische Übersetzungen aller für den Fahrer sichtbaren Strings im Workout. Jeder Spracheintrag hat dieselbe Form:

"strings": {
  "en": {
    "name": "Sweet Spot 30",
    "description": "A short sweet-spot workout.",
    "labels": { "warmup": "Warmup", "work": "Sweet Spot", "cooldown": "Cooldown" },
    "cues":   { "work:0": "Settle in", "work:1": "Halfway" }
  },
  "de": {
    "name": "Sweet Spot 30",
    "description": "Ein kurzes Sweet-Spot-Training.",
    "labels": { "warmup": "Aufwärmen", "work": "Sweet Spot", "cooldown": "Ausrollen" },
    "cues":   { "work:0": "Locker einrollen", "work:1": "Halbzeit" }
  }
}

Hinweis-Schlüssel folgen dem Muster <intervalId>:<cueIndex> — der erste Hinweis auf dem work-Intervall hat also den Schlüssel work:0.

Für jeden vom Fahrer sichtbaren String wählt die App die am besten passende Sprache in dieser Reihenfolge:

  1. strings[<rider-locale>] — die eigene Sprache des Fahrers.
  2. strings[primaryLocale] — die Sprache des Autors.
  3. strings["en"] — universeller Fallback.
  4. Das Feld auf oberster Ebene (programName, Intervall-label, Hinweis-text).

Strings, die aus einer anderen Sprache als der des Fahrers angezeigt werden, erscheinen auf Workout-Karten und im Cockpit kursiv, damit der Fahrer erkennt, welche Strings noch nicht übersetzt sind.

See also: KI-Prompt-Skills — the AI Coach can generate strings blocks for additional locales when prompted.

Wiederholungsgruppen

Für sich wiederholende Strukturen beschreibt eine Wiederholungsgruppe die Einheit einmal und teilt der App mit, wie oft sie abgespielt werden soll. Wiederholungsgruppen werden beim Import in einzelne Blöcke entfaltet, sodass der Fahrer während der Fahrt jeden Block im Streifen der kommenden Intervalle sieht.

{
  "intervals": [
    { "id": "warmup", "duration": 600, "targetPowerPercent": 50, "intensityZone": "Z1", "label": "Warmup", "intervalType": "WARMUP" },
    {
      "repeat": 4,
      "intervals": [
        { "id": "on",  "duration": 480, "targetPowerPercent": 95, "intensityZone": "Z4", "label": "Threshold" },
        { "id": "off", "duration": 240, "targetPowerPercent": 55, "intensityZone": "Z1", "label": "Recovery" }
      ]
    },
    { "id": "cooldown", "duration": 600, "targetPowerPercent": 50, "intensityZone": "Z1", "label": "Cooldown", "intervalType": "COOLDOWN" }
  ]
}

Das obige Beispiel entfaltet sich zu 1 Aufwärmen + 4×(Schwelle + Erholung) + 1 Auslaufen = 10 Blöcke. Wiederholungsgruppen lassen sich verschachteln, aber flach ist für die Lesbarkeit zu bevorzugen.

Workout-Typen & Varianten

Das Feld workoutType wählt das Paradigma; variant wählt einen Untertyp darin.

workoutTypeWas es istErforderliche Intervall-Form
POWER (Standard)FTP-verankerte Intervalle. Der Trainer hält in ERG die Soll-Wattzahl oder folgt in SIM Widerstandskurven.Jedes Intervall hat targetPowerPercent (und optional targetPowerEndPercent für Rampen).
HR_ZONEHerzfrequenz-gesteuerte Intervalle. Der Trainer passt die Wattzahl live an, um die HF des Fahrers in der Ziel-Zone zu halten — nützlich, wenn die kardiovaskuläre Belastung die Trainings-Metrik ist (Erholung, Grundlage, polarisiertes Training).Jedes Intervall hat targetHrZone (1–5). Der START-Knopf zeigt HF-MESSER, bis der HRM verbunden ist.
ROUTESteigungs-gesteuerte Simulations-Fahrten. Der Trainer folgt dem Höhenprofil aus routeProfile; der Fahrer wählt Trittfrequenz und Übersetzung.Intervalle sind meist leer oder enthalten einen einzelnen Platzhalter über die volle Länge. Der eigentliche Fahrt-Inhalt steckt in routeProfile.

Das Feld variant wählt einen Untertyp:

Pakete (.ytwpack)

Wenn du eine kuratierte Sammlung von Workouts auf einmal willst, bündelt das .ytwpack-Format viele .ytw-Dateien zusammen mit einem paketweiten Manifest. Eine .ytwpack ist unter der Haube ein ZIP-Archiv — benenne sie in .zip um und entpacke sie, um den Inhalt zu sehen, oder importiere sie über den Paket-Installer von Your Trainer, um alle Workouts in einem Tipp installiert zu bekommen.

Ein .ytwpack-Archiv enthält:

Das Paket-Manifest enthält genug Informationen für ein Installations-Entscheidungs-Sheet, ohne dass jedes Workout geöffnet werden muss. Felder auf oberster Ebene:

FeldTypBeschreibung
schema_version erforderlichintegerAktuell immer 1.
pack_id erforderlichstringStabile kebab-case-Kennung (z. B. sweet-spot).
name erforderlichstringAnzeigename, der im Paket-Katalog angezeigt wird.
description erforderlichstringEin- oder zweisätzige Zusammenfassung, die sichtbar ist, bevor der Fahrer zum Installieren tippt.
version erforderlichstring (SemVer)MAJOR.MINOR.PATCH, optional -prerelease. Patch für Inhaltskorrekturen; Minor für zusätzliche Workouts; Major für brechende Schema-Änderungen. Wird im veröffentlichten Dateinamen eingebettet (v1.0.2.ytwpack).
content_hash erforderlichstringsha256: über die nach Slug sortierte Aneinanderreihung der Bytes jeder .ytw-Datei. Bleibt über Neu-Generierungen unveränderten Inhalts stabil; ändert sich jedes Mal, wenn sich die enthaltenen Workouts ändern.
generated_at erforderlichstring (ISO 8601)UTC-Zeitstempel.
set erforderlichstringpower oder hr-zone — die Workout-Familie, zu der dieses Paket gehört.
category erforderlichstringUntertaxonomie innerhalb des Sets (z. B. sweet-spot).
workout_count erforderlichintegerAnzahl der .ytw-Einträge im Paket.
total_ride_time_seconds erforderlichintegerSumme der Dauer jedes Workouts im Paket.
experience_level erforderlichstringBerechnet aus der Schwierigkeits-Bandbreite der Inhalte — einer von beginner / intermediate / advanced / mixed. Kleinbuchstaben im Wire-Format; die App schreibt für die Anzeige groß.
hrm_required erforderlichbooleanTrue, wenn irgendein Workout im Paket HR_ZONE verwendet.
type_mix erforderlichobjectProzentsatz der Gesamt-Fahrtzeit pro Kategorie (summiert sich zu 100). Steuert das In-App-Type-Mix-Donut auf dem Installations-Sheet.
duration_histogram erforderlichobjectAnzahl der Workouts pro Dauer-Bin: 0-30, 30-60, 60-90, 90+ (Minuten). Steuert das Dauer-Diagramm auf dem Installations-Sheet.
contents erforderlicharrayVollständige Einträge pro Workout — Obermenge der Eintragsform des Bibliotheks-Manifests; jeder trägt slug, name, duration_seconds, Zusammenfassungs-Metriken, plus ein sparkline-Array für das Thumbnail-Rendering.

Zwei Installations-Wege für eine heruntergeladene .ytwpack:

Beispiel-Paket-Manifest (mit gekürztem contents zur besseren Lesbarkeit):

{
  "schema_version": 1,
  "pack_id": "sweet-spot",
  "name": "Sweet Spot",
  "description": "26 sweet-spot sessions across classic intervals, sustained stacks, and over-unders.",
  "version": "1.0.2",
  "content_hash": "sha256:9432a3a76015158dc71ec63…",
  "generated_at": "2025-05-28T00:00:00Z",
  "set": "power",
  "category": "sweet-spot",
  "workout_count": 26,
  "total_ride_time_seconds": 119340,
  "experience_level": "intermediate",
  "hrm_required": false,
  "type_mix":   { "sweet-spot": 100 },
  "duration_histogram": { "0-30": 0, "30-60": 5, "60-90": 12, "90+": 9 },
  "contents": [
    { "slug": "sweet-spot-3x10min-at-88pct-ftp",  "name": "Sweet Spot 3×10min @ 88% FTP",  "duration_seconds": 3300, "tss": 55.8,  "intensity_factor": 0.764, "sparkline": […] },
    { "slug": "sweet-spot-3x15min-at-90pct-ftp",  "name": "Sweet Spot 3×15min @ 90% FTP",  "duration_seconds": 4500, "tss": 81.6,  "intensity_factor": 0.808, "sparkline": […] }
    /* … 24 more workouts … */
  ]
}

Bibliotheks- & Paket-Manifeste

Zwei Manifeste werden zusammen mit den herunterladbaren Artefakten veröffentlicht. Beide sind reines JSON; beide werden durch JSON-Schema-Dokumente beschrieben, die du direkt abrufen kannst.

URLWas es auflistetJSON Schema
library/manifest.json Jede kuratierte .ytw in der Bibliothek — Metadaten pro Workout für Browse-/Such-/Filter-Clients. Listet außerdem die verfügbaren .ytwpack-Downloads auf (Dateipfad, Version, Content-Hash, Type-Mix-Zusammenfassung, Icon-URL). /schemas/workout-manifest.json
packs/manifest.json Paket-Katalog-Endpunkt: jede veröffentlichte .ytwpack mit Zusammenfassungs-Metadaten. Dieselbe Eintragsform pro Paket wie das packs-Array des Bibliotheks-Manifests; die In-App-Paket-Bibliothek holt das bei einer vom Fahrer ausgelösten Aktualisierung. /schemas/workout-manifest.json
(innerhalb jeder .ytwpack) Paket-Manifest, als manifest.json im Wurzelverzeichnis des Archivs mitgeführt — die obige Tabelle dokumentiert seine Form. /schemas/workout-pack-manifest.json

Wenn du Tools baust, die die Bibliothek konsumieren — einen eigenen Workout-Browser, einen Workout-Konverter, der auf .zwo abzielt, ein Coach-Dashboard, das Pakete darstellt — sind das die Verträge, gegen die du validieren solltest. Dieselbe Eintragsform pro Workout taucht in beiden Manifesten in den contents-/workouts-Arrays auf, sodass ein Client, der das eine verarbeitet, auch das andere verarbeitet.

Ausgearbeitete Beispiele

Rampen-Intervall

Ein 5-minütiges Aufwärmen, das per linearer Interpolation von 40 % FTP auf 75 % FTP rampt:

{
  "id": "rampup",
  "duration": 300,
  "targetPowerPercent": 40,
  "targetPowerEndPercent": 75,
  "intensityZone": "Z1",
  "label": "Ramp up",
  "intervalType": "WARMUP"
}

Over-Under

Drei Sätze à 2 Minuten bei 95 % FTP / 1 Minute bei 105 % FTP, ausgedrückt als Wiederholungsgruppe:

{
  "repeat": 3,
  "intervals": [
    { "id": "under", "duration": 120, "targetPowerPercent": 95,  "intensityZone": "Z4", "label": "Under" },
    { "id": "over",  "duration": 60,  "targetPowerPercent": 105, "intensityZone": "Z5", "label": "Over"  }
  ]
}

HF-Zonen-Workout

30-minütige Z2-Ausdauer-Fahrt mit einem 3-minütigen Z4-Push in der Mitte:

{
  "programId": "hr-z2-with-surge",
  "programName": "Z2 with a Z4 surge",
  "description": "Steady Zone 2 with a single 3-minute Zone 4 surge.",
  "totalDuration": 1800,
  "workoutType": "HR_ZONE",
  "primaryLocale": "en",
  "intervals": [
    { "id": "warmup",  "duration": 300,  "targetHrZone": 1, "intensityZone": "Z1", "label": "Warmup", "intervalType": "WARMUP" },
    { "id": "endure1", "duration": 600,  "targetHrZone": 2, "intensityZone": "Z2", "label": "Endurance" },
    { "id": "surge",   "duration": 180,  "targetHrZone": 4, "intensityZone": "Z4", "label": "Surge" },
    { "id": "endure2", "duration": 420,  "targetHrZone": 2, "intensityZone": "Z2", "label": "Endurance" },
    { "id": "cooldown","duration": 300,  "targetHrZone": 1, "intensityZone": "Z1", "label": "Cooldown", "intervalType": "COOLDOWN" }
  ]
}

Mehrsprachig

Das minimale Sweet Spot-Beispiel mit EN-, DE- und NL-strings-Blöcken. Dasselbe Workout, drei native Erlebnisse:

{
  "programId": "my-sweet-spot",
  "programName": "Sweet Spot 30",
  "description": "A short sweet-spot workout.",
  "totalDuration": 1800,
  "workoutType": "POWER",
  "primaryLocale": "en",
  "intervals": [
    { "id": "warmup",   "duration": 300,  "targetPowerPercent": 50, "intensityZone": "Z1", "label": "Warmup",     "intervalType": "WARMUP"   },
    { "id": "work",     "duration": 1200, "targetPowerPercent": 88, "intensityZone": "Z3", "label": "Sweet Spot", "intervalType": "INTERVAL",
      "cues": [
        { "offsetSec": 0,   "text": "Settle in" },
        { "offsetSec": 600, "text": "Halfway" }
      ]
    },
    { "id": "cooldown", "duration": 300,  "targetPowerPercent": 50, "intensityZone": "Z1", "label": "Cooldown",   "intervalType": "COOLDOWN" }
  ],
  "strings": {
    "en": {
      "name": "Sweet Spot 30",
      "description": "A short sweet-spot workout.",
      "labels": { "warmup": "Warmup", "work": "Sweet Spot", "cooldown": "Cooldown" },
      "cues":   { "work:0": "Settle in", "work:1": "Halfway" }
    },
    "de": {
      "name": "Sweet Spot 30",
      "description": "Ein kurzes Sweet-Spot-Training.",
      "labels": { "warmup": "Aufwärmen", "work": "Sweet Spot", "cooldown": "Ausrollen" },
      "cues":   { "work:0": "Locker einrollen", "work:1": "Halbzeit" }
    },
    "nl": {
      "name": "Sweet Spot 30",
      "description": "Een korte sweet-spot-training.",
      "labels": { "warmup": "Inrijden", "work": "Sweet Spot", "cooldown": "Uitrijden" },
      "cues":   { "work:0": "Rustig inrijden", "work:1": "Halverwege" }
    }
  }
}

Häufige Fallstricke

Referenz

Für programmatische Format-Spec-Lookups (Feldtabellen, Beispiele, Constraints, Glossar) ist die kanonische maschinenlesbare Quelle der Your Trainer MCP — rufe get_format_spec, get_canonical_examples, get_format_constraints oder get_format_glossary aus jedem MCP-Client. Diese Tools liefern aus derselben Wissensbasis, die diese Seite speist; weicht eine Tool-Antwort einmal von dieser Seite ab, ist der MCP kanonisch und diese Seite veraltet.

JSON-Schemas (maschinenlesbare Verträge für Clients, die auf diesen Formaten aufbauen):

← Zurück zu Handbuch & Anleitungen