Schema dell'allenamento

Ultimo aggiornamento: 2026-05-29

Your Trainer è un'app di ciclismo indoor multi-ciclista per tablet Android. Controllo dello smart trainer con dati locali + controllo locale. Acquisto unico.

Il file di allenamento .ytw è semplice JSON — scrivilo in qualsiasi editor di testo, importalo tramite il foglio di condivisione, condividilo con gli amici. L'editor visivo gestisce i casi comuni; lo schema è la via d'uscita quando ti serve il controllo totale.

Quando scrivere a mano

La maggior parte dei ciclisti non avrà mai bisogno di questa pagina — l'editor visivo degli allenamenti e l'AI Workout Coach coprono tutto, da una sessione di soglia 4×8 a uno stack di microburst. Ricorri allo schema quando:

Esempio minimo

Il file .ytw valido più breve è un programma con un intervallo. Salvalo con estensione .ytw e condividilo in Your Trainer.

{
  "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" }
  ]
}

Campi di primo livello

L'oggetto di primo livello descrive un programma di allenamento. I campi obbligatori sono contrassegnati.

CampoTipoDescrizione
programId obbligatoriostringaIdentificatore stabile. Usa kebab-case (my-sweet-spot). La chiave univoca dell'allenamento nella tua libreria — reimportare un file con lo stesso programId aggiorna la voce esistente invece di crearne un duplicato.
programName obbligatoriostringaNome visualizzato nella lingua principale del ciclista.
description obbligatoriostringaDescrizione di una o due frasi mostrata sulla scheda dell'allenamento.
totalDuration obbligatoriointero (secondi)Durata totale dell'allenamento. L'app la ricalcola dagli intervalli al salvataggio, quindi è sicuro lasciarla incoerente durante la stesura.
intervals obbligatorioarrayElenco ordinato di oggetti intervallo o gruppi di ripetizione.
workoutTypestringaFamiglia di allenamento: POWER (predefinito), HR_ZONE o ROUTE. Vedi Tipi di allenamento.
variantstringaSotto-forma all'interno della famiglia: STANDARD (predefinito) o RAMP_TEST.
primaryLocalestringa (BCP-47)Lingua in cui sono state scritte le stringhe. Predefinito "en". Guida la catena di fallback tra le lingue.
categorystringaCategorizzazione libera (es. "threshold", "endurance"). Facoltativo.
difficultyintero (1–5)Difficoltà soggettiva. Compare sulla scheda dell'allenamento.
isUserCreatedbooleanoTrue per gli allenamenti creati nell'app dal ciclista; false per gli allenamenti importati o inclusi. Predefinito false.
isFavoritebooleanoFlag di fissaggio in alto. I ciclisti lo attivano nell'app; di solito viene omesso nei file condivisi.
routeProfilearray di { distanceMeters, elevationMeters }Profilo altimetrico completo per gli allenamenti ROUTE. Null per POWER e HR_ZONE.
stringsoggetto (lingua → LocaleStrings)Traduzioni per ciascuna lingua di nome, descrizione, etichette degli intervalli e suggerimenti.

Campi dell'intervallo

Ogni oggetto intervallo descrive un blocco dell'allenamento. La forma del blocco dipende dal workoutType del genitore — i blocchi Power usano percentuali di potenza, i blocchi HR-Zone usano un target di zona.

CampoTipoDescrizione
duration obbligatoriointero (secondi)Lunghezza del blocco in secondi.
targetPowerPercent obbligatorio per powerintero (% di FTP)Target di potenza per gli allenamenti POWER. Mutuamente esclusivo con targetHrZone.
targetPowerEndPercentintero (% di FTP)Potenza finale facoltativa per le rampe. Quando è presente, il target in watt interpola linearmente da targetPowerPercenttargetPowerEndPercent lungo tutto il blocco.
targetHrZone obbligatorio per FCintero (1–5)Zona FC per gli allenamenti HR_ZONE. Mutuamente esclusivo con targetPowerPercent.
intensityZone obbligatoriostringaToken visivo di zona: Z1Z5. Determina il colore nella visualizzazione del terreno. Vedi Zone di allenamento.
intervalTypestringaWARMUP, COOLDOWN o INTERVAL (predefinito). I blocchi di riscaldamento e defaticamento sono esclusi dai riepiloghi che considerano solo il lavoro (potenza media dei blocchi di lavoro, tempo in zona per la parte di lavoro, ecc.).
label obbligatoriostringaTesto visualizzato sul blocco nella lingua principale del ciclista. Le varianti per altre lingue stanno in strings.<locale>.labels.
idstringaSlug stabile — la chiave usata in strings.<locale>.labels e nella composizione delle chiavi dei suggerimenti. Consigliato per ogni allenamento distribuito con traduzioni.
autoLabelbooleanoTrue quando l'etichetta è stata generata da un preset dell'editor anziché digitata dal ciclista. Le etichette automatiche sono localizzate da Your Trainer stesso e non richiedono voci per lingua in strings. Predefinito false.
cadenceTargetintero (RPM)Target di cadenza facoltativo per il blocco (es. 60 per salite a bassa cadenza, 100 per esercizi di spin-up).
cuesarray di CoachingCueSuggerimenti di coaching che si attivano durante il blocco.

Suggerimenti di coaching

Un suggerimento di coaching è un breve overlay di testo che appare nella cabina di pilotaggio durante una pedalata. Ogni suggerimento ha un offset all'interno dell'intervallo che lo contiene, il testo da mostrare e per quanto tempo lasciarlo sullo schermo.

CampoTipoDescrizione
offsetSec obbligatoriointero (secondi)Secondi dall'inizio dell'intervallo genitore in cui il suggerimento si attiva.
text obbligatoriostringaTesto del suggerimento nella lingua principale dell'allenamento. Le varianti per altre lingue stanno in strings.<locale>.cues, indicizzate da <intervalId>:<cueIndex>.
durationSecintero (secondi)Per quanto tempo il suggerimento resta a schermo. Predefinito 5.

Esempio di intervallo con tre suggerimenti (la composizione della chiave usa l'id dell'intervallo genitore + l'indice del suggerimento nell'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." }
  ]
}

Stringhe localizzate & catena di fallback

Il blocco strings contiene le traduzioni per ciascuna lingua di ogni stringa dell'allenamento visibile al ciclista. Ogni voce di lingua ha la stessa forma:

"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" }
  }
}

Le chiavi dei suggerimenti seguono il pattern <intervalId>:<cueIndex> — quindi il primo suggerimento dell'intervallo work ha chiave work:0.

Per ogni stringa visibile al ciclista, l'app sceglie la migliore corrispondenza di lingua in questo ordine:

  1. strings[<rider-locale>] — la lingua del ciclista stesso.
  2. strings[primaryLocale] — la lingua dell'autore.
  3. strings["en"] — fallback universale.
  4. Il campo di primo livello (programName, label dell'intervallo, text del suggerimento).

Le stringhe mostrate da una lingua diversa da quella del ciclista appaiono in corsivo sulle schede degli allenamenti e nella cabina di pilotaggio, così il ciclista capisce quali stringhe non sono ancora state tradotte.

See also: Skill di prompt AI — the AI Coach can generate strings blocks for additional locales when prompted.

Gruppi di ripetizione

Per le strutture ripetitive, un gruppo di ripetizione scrive l'unità una sola volta e dice all'app quante volte riprodurla. I gruppi di ripetizione vengono espansi in blocchi individuali all'importazione, così il ciclista vede ogni blocco nella striscia degli intervalli in arrivo durante la pedalata.

{
  "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" }
  ]
}

L'esempio sopra si espande in 1 riscaldamento + 4×(soglia + recupero) + 1 defaticamento = 10 blocchi. I gruppi di ripetizione possono annidarsi, ma la struttura piatta è preferibile per leggibilità.

Tipi di allenamento & varianti

Il campo workoutType seleziona il paradigma; variant seleziona una sotto-forma al suo interno.

workoutTypeCos'èForma dell'intervallo richiesta
POWER (predefinito)Intervalli ancorati all'FTP. Il rullo segue il target in watt in ERG, oppure le curve di resistenza in SIM.Ogni intervallo ha targetPowerPercent (e facoltativamente targetPowerEndPercent per le rampe).
HR_ZONEIntervalli guidati dalla frequenza cardiaca. Il rullo regola i watt in tempo reale per mantenere la FC del ciclista nella zona target — utile quando la metrica di allenamento è il carico cardiovascolare (recupero, base, lavoro polarizzato).Ogni intervallo ha targetHrZone (1–5). Il pulsante START riporta COLLEGA HRM finché l'HRM non è collegato.
ROUTEPedalate di simulazione guidate dalla pendenza. Il rullo segue il profilo altimetrico da routeProfile; il ciclista sceglie cadenza e rapporto.Gli intervalli di solito sono vuoti o contengono un singolo segnaposto a lunghezza piena. Il contenuto reale della pedalata risiede in routeProfile.

Il campo variant seleziona una sotto-forma:

Pacchetti (.ytwpack)

Quando vuoi un lotto curato di allenamenti in un colpo solo, il formato .ytwpack raggruppa molti file .ytw insieme a un manifesto del pacchetto. Un .ytwpack è in realtà un archivio ZIP — rinominalo in .zip e decomprimilo per vederne il contenuto, oppure importalo tramite l'installer di pacchetti di Your Trainer per installare ogni allenamento con un solo tocco.

Un archivio .ytwpack contiene:

Il manifesto del pacchetto contiene informazioni sufficienti per una scheda di decisione di installazione senza dover aprire ogni allenamento. Campi di primo livello:

CampoTipoDescrizione
schema_version obbligatoriointeroAttualmente sempre 1.
pack_id obbligatoriostringaIdentificatore stabile in kebab-case (es. sweet-spot).
name obbligatoriostringaNome visualizzato nel catalogo dei pacchetti.
description obbligatoriostringaRiepilogo di una o due frasi visibile prima che il ciclista tocchi per installare.
version obbligatoriostringa (SemVer)MAJOR.MINOR.PATCH, facoltativo -prerelease. Patch per correzioni di contenuti; minor per allenamenti aggiuntivi; major per modifiche di schema che rompono la compatibilità. Incluso nel nome del file pubblicato (v1.0.2.ytwpack).
content_hash obbligatoriostringasha256: sulla concatenazione dei byte di ogni file .ytw ordinati per slug. Stabile attraverso le rigenerazioni di contenuti immutati; cambia ogni volta che gli allenamenti all'interno cambiano.
generated_at obbligatoriostringa (ISO 8601)Timestamp UTC.
set obbligatoriostringapower o hr-zone — la famiglia di allenamento a cui appartiene questo pacchetto.
category obbligatoriostringaSotto-tassonomia all'interno del set (es. sweet-spot).
workout_count obbligatoriointeroNumero di voci .ytw nel pacchetto.
total_ride_time_seconds obbligatoriointeroSomma delle durate di ogni allenamento nel pacchetto.
experience_level obbligatoriostringaCalcolato dall'intervallo di difficoltà dei contenuti — uno tra beginner / intermediate / advanced / mixed. Formato wire minuscolo; l'app lo capitalizza per la visualizzazione.
hrm_required obbligatoriobooleanoTrue se qualche allenamento nel pacchetto usa HR_ZONE.
type_mix obbligatoriooggettoPercentuale per categoria del tempo totale di pedalata (somma 100). Alimenta il grafico a ciambella del mix di tipi nella scheda di installazione in-app.
duration_histogram obbligatoriooggettoConteggio degli allenamenti per intervallo di durata: 0-30, 30-60, 60-90, 90+ (minuti). Alimenta il grafico delle durate della scheda di installazione.
contents obbligatorioarrayVoci complete per ciascun allenamento — superset della forma della voce nel manifesto di libreria; ognuna porta slug, name, duration_seconds, metriche di riepilogo, oltre a un array sparkline per il rendering della miniatura.

Due strade di installazione per un .ytwpack scaricato:

Esempio di manifesto di pacchetto (con contents troncato per leggibilità):

{
  "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 … */
  ]
}

Manifesti di libreria & pacchetto

Due manifesti vengono pubblicati insieme agli artefatti scaricabili. Entrambi sono semplici JSON; entrambi sono descritti da documenti JSON Schema che puoi recuperare direttamente.

URLCosa elencaJSON Schema
library/manifest.json Ogni .ytw curato nella libreria — metadati per allenamento per i client di sfoglia / ricerca / filtro. Elenca anche i download .ytwpack disponibili (percorso del file, versione, hash dei contenuti, riepilogo del mix di tipi, URL dell'icona). /schemas/workout-manifest.json
packs/manifest.json Endpoint del catalogo dei pacchetti: ogni .ytwpack pubblicato con metadati di riepilogo. Stessa forma di voce per pacchetto dell'array packs del manifesto di libreria; la Pack Library in-app la recupera all'aggiornamento avviato dal ciclista. /schemas/workout-manifest.json
(dentro ogni .ytwpack) Manifesto per pacchetto trasportato come manifest.json nella radice dell'archivio — la tabella sopra ne documenta la forma. /schemas/workout-pack-manifest.json

Se stai costruendo strumenti che consumano la libreria — un browser di allenamenti personalizzato, un convertitore di allenamenti che produce .zwo, una dashboard per allenatori che mostra i pacchetti — questi sono i contratti contro cui validare. La stessa forma di voce per allenamento appare in entrambi gli array contents / workouts dei manifesti, quindi un client che gestisce uno gestisce anche l'altro.

Esempi pratici

Intervallo a rampa

Un riscaldamento di 5 minuti che sale dal 40 % di FTP al 75 % di FTP tramite interpolazione lineare:

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

Over-under

Tre serie da 2 minuti al 95 % di FTP / 1 minuto al 105 % di FTP, espresse come gruppo di ripetizione:

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

Allenamento con zone FC

Pedalata di resistenza di 30 minuti in Z2 con un'accelerazione di 3 minuti in Z4 nel mezzo:

{
  "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" }
  ]
}

Multilingue

L'esempio minimo Sweet Spot con i blocchi strings per EN + DE + NL. Stesso allenamento, tre esperienze native:

{
  "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" }
    }
  }
}

Errori comuni

Riferimento

Per ricerche programmatiche di spec di formato (tabelle di campo, esempi, vincoli, glossario), la fonte canonica leggibile dalla macchina è il Your Trainer MCP — chiama get_format_spec, get_canonical_examples, get_format_constraints o get_format_glossary da qualsiasi client MCP. Questi tool servono dallo stesso registro di conoscenza che alimenta questa pagina; se la risposta di un tool dovesse mai divergere da questa pagina, il MCP è canonico e questa pagina è obsoleta.

JSON Schema (contratti leggibili da macchina per i client che costruiscono su questi formati):

← Torna a Manuale & Guide