ワークアウトスキーマ

最終更新: 2026-05-29

Your Trainer は、複数ライダー対応の Android タブレット向け屋内サイクリングアプリです。スマートトレーナー制御、ローカルデータ + ローカル制御。買い切り型。

.ytw ワークアウトファイルはプレーンな JSON です — 任意のテキストエディタで作成し、共有シート経由でインポートして、友人と共有できます。ビジュアルエディタは一般的なケースに対応しますが、スキーマは完全な制御が必要なときの逃げ道です。

手書き作成すべきとき

ほとんどのライダーはこのページを必要としません — ビジュアルワークアウトエディタと AI ワークアウトコーチが、4×8 の閾値セッションからマイクロバーストスタックまですべてをカバーします。スキーマに手を伸ばすのは次のような場合です:

最小限の例

最短の有効な .ytw ファイルは、1 つのインターバルを持つ 1 つのプログラムです。.ytw 拡張子で保存し、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" }
  ]
}

トップレベルフィールド

トップレベルオブジェクトは 1 つのワークアウトプログラムを表します。必須フィールドはフラグで示されています。

フィールド説明
programId 必須string安定した識別子。ケバブケース(my-sweet-spot)を使ってください。ライブラリ内でのワークアウトの一意キーです — 同じ programId のファイルを再インポートすると、重複を作らず既存のエントリを更新します。
programName 必須stringライダーの主要ロケールでの表示名。
description 必須stringワークアウトカードに表示される 1〜2 文の説明。
totalDuration 必須integer(秒)ワークアウト全体の長さ。アプリは保存時にインターバルから再計算するため、作成中は一貫していなくても問題ありません。
intervals 必須arrayインターバルオブジェクト または リピートグループ の順序付きリスト。
workoutTypestringワークアウトファミリー: POWER(デフォルト)、HR_ZONE、または ROUTEワークアウトタイプ を参照。
variantstringファミリー内のサブ形状: STANDARD(デフォルト)または RAMP_TEST
primaryLocalestring(BCP-47)文字列が作成されたロケール。デフォルトは "en"。クロスロケールフォールバックチェーンを駆動します。
categorystring自由記述のカテゴリ分け(例: "threshold""endurance")。オプション。
difficultyinteger(1〜5)主観的な難易度。ワークアウトカードに表示されます。
isUserCreatedbooleanライダーがアプリ内で作成したワークアウトは true、インポートまたは同梱されたワークアウトは false。デフォルトは false
isFavoritebooleanトップ固定フラグ。ライダーがアプリ内で切り替えます。共有ファイルでは通常省略されます。
routeProfilearray of { distanceMeters, elevationMeters }ROUTE ワークアウト用の完全な標高プロファイル。POWER と HR_ZONE では null。
stringsobject (locale → LocaleStrings)名前、説明、インターバルラベル、キューのロケール別翻訳。

インターバルフィールド

各インターバルオブジェクトはワークアウトの 1 ブロックを表します。ブロックの形状は親の workoutType によって決まります — パワーブロックはパワーパーセンテージを、心拍ゾーンブロックはゾーンターゲットを使います。

フィールド説明
duration 必須integer(秒)ブロックの長さ(秒)。
targetPowerPercent パワー必須integer(FTP の %)POWER ワークアウトのパワーターゲット。targetHrZone とは相互排他的です。
targetPowerEndPercentinteger(FTP の %)オプションのランプ終了パワー。存在する場合、ターゲットワット数はブロック全体で targetPowerPercenttargetPowerEndPercent へ線形に補間されます。
targetHrZone 心拍必須integer(1〜5)HR_ZONE ワークアウト用の心拍ゾーン。targetPowerPercent とは相互排他的です。
intensityZone 必須stringビジュアルゾーントークン: Z1Z5。地形ビジュアライゼーションの色を決定します。トレーニングゾーン を参照。
intervalTypestringWARMUPCOOLDOWN、または INTERVAL(デフォルト)。ウォームアップとクールダウンのブロックはワーク専用サマリー(ワークブロックの平均パワー、ワーク部分のゾーン滞在時間など)から除外されます。
label 必須stringライダーの主要ロケールでブロックに表示されるテキスト。クロスロケールバリアントは strings.<locale>.labels に格納されます。
idstring安定したスラッグ — strings.<locale>.labels およびキューキー構成で使用されるキーです。翻訳付きで配布するワークアウトには推奨されます。
autoLabelbooleanラベルがライダーによって入力されたものではなくエディタプリセットで生成された場合に true。自動ラベルは Your Trainer 自体がローカライズするため、strings 内にロケール別エントリは不要です。デフォルトは false
cadenceTargetinteger(RPM)ブロック用のオプションのケイデンスターゲット(例: 低ケイデンスのクライミングなら 60、スピンアップドリルなら 100)。
cuesarray of CoachingCueブロック中に発火するコーチングキュー。

コーチングキュー

コーチングキューは、ライド中にコックピットに表示される短いテキストオーバーレイです。各キューは親インターバル内のオフセット、表示するテキスト、画面に表示する時間の長さを持ちます。

フィールド説明
offsetSec 必須integer(秒)キューが発火する親インターバルの開始からの秒数。
text 必須stringワークアウトの主要ロケールでのキューテキスト。クロスロケールバリアントは strings.<locale>.cues 内に <intervalId>:<cueIndex> をキーとして格納されます。
durationSecinteger(秒)キューが画面に表示される時間の長さ。デフォルトは 5

3 つのキューを持つインターバルの例(キー構成は親インターバルの id と配列内のキューのインデックスを使います):

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

ローカライズ文字列とフォールバックチェーン

strings ブロックは、ワークアウト内のすべてのライダー向け文字列のロケール別翻訳を保持します。各ロケールエントリは同じ形状です:

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

キューキーは <intervalId>:<cueIndex> のパターンに従います — そのため work インターバルの最初のキューは work:0 をキーとします。

各ライダー向け文字列について、アプリは次の順序で最適なロケール一致を選びます:

  1. strings[<rider-locale>] — ライダー自身のロケール。
  2. strings[primaryLocale] — 作成者のロケール。
  3. strings["en"] — 普遍的なフォールバック。
  4. トップレベルフィールド(programName、インターバル label、キュー text)。

ライダー自身のロケール以外から表示される文字列は、ワークアウトカードとコックピットで斜体で表示されるため、ライダーはどの文字列がまだ翻訳されていないかを判別できます。

See also: AI プロンプトスキル — the AI Coach can generate strings blocks for additional locales when prompted.

リピートグループ

繰り返し構造には、リピートグループでユニットを 1 回作成し、アプリに何回再生するかを伝えます。リピートグループはインポート時に個別のブロックに展開されるため、ライダーはライド中の次のインターバルストリップで各ブロックを確認できます。

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

上記の例は 1 つのウォームアップ + 4×(閾値 + リカバリー)+ 1 つのクールダウン = 10 ブロックに展開されます。リピートグループはネスト可能ですが、可読性のためにフラットの方が望ましいです。

ワークアウトタイプとバリアント

workoutType フィールドはパラダイムを選択し、variant はその中のサブ形状を選択します。

workoutType概要必要なインターバル形状
POWER(デフォルト)FTP を基準としたインターバル。トレーナーは ERG でターゲットワット数を維持するか、SIM でレジスタンスカーブに従います。各インターバルには targetPowerPercent(ランプの場合はオプションで targetPowerEndPercent)があります。
HR_ZONE心拍駆動のインターバル。トレーナーはライダーの心拍をターゲットゾーン内に保つようにワット数をリアルタイムで調整します — 心血管負荷がトレーニング指標となる場合(リカバリー、ベース、ポラライズドワーク)に有用です。各インターバルには targetHrZone(1〜5)があります。HRM が接続されるまで START ボタンは HRM 接続 と表示されます。
ROUTEスロープ駆動のシミュレーションライド。トレーナーは routeProfile の標高プロファイルに従います。ライダーはケイデンスとギアリングを選択します。インターバルは通常空であるか、全長プレースホルダー 1 つを含みます。実際のライドコンテンツは routeProfile 内にあります。

variant フィールドはサブ形状を選択します:

パック(.ytwpack)

厳選されたワークアウトのバッチを一度に欲しいときは、.ytwpack 形式が多数の .ytw ファイルをパック単位のマニフェストと一緒にまとめます。.ytwpack は内部的には ZIP アーカイブです — .zip にリネームして解凍すれば中身を確認できますし、Your Trainer のパックインストーラー経由でインポートすれば、すべてのワークアウトをワンタップでインストールできます。

.ytwpack アーカイブには次が含まれます:

パックマニフェストは、すべてのワークアウトを開かなくてもインストール判断シートに必要な情報を保持します。トップレベルフィールド:

フィールド説明
schema_version 必須integer現在は常に 1
pack_id 必須string安定したケバブケース識別子(例: sweet-spot)。
name 必須stringパックカタログに表示される表示名。
description 必須stringライダーがインストールをタップする前に表示される 1〜2 文の要約。
version 必須string(SemVer)MAJOR.MINOR.PATCH、オプションで -prerelease。コンテンツ修正はパッチ、追加ワークアウトはマイナー、破壊的スキーマ変更はメジャー。公開ファイル名に埋め込まれます(v1.0.2.ytwpack)。
content_hash 必須stringすべての .ytw ファイルのバイトをスラッグでソートして連結したものに対する sha256:。変更されていないコンテンツの再生成では安定し、内部のワークアウトが変わるたびに更新されます。
generated_at 必須string(ISO 8601)UTC タイムスタンプ。
set 必須stringpower または hr-zone — このパックが属するワークアウトファミリー。
category 必須stringセット内のサブタクソノミー(例: sweet-spot)。
workout_count 必須integerパック内の .ytw エントリ数。
total_ride_time_seconds 必須integerパック内のすべてのワークアウトの長さの合計。
experience_level 必須stringコンテンツの難易度範囲から計算されます — beginner / intermediate / advanced / mixed のいずれか。ワイヤー形式は小文字で、アプリが表示用に大文字化します。
hrm_required 必須booleanパック内のワークアウトのいずれかが HR_ZONE を使用する場合は true。
type_mix 必須object総ライド時間に対するカテゴリ別パーセンテージ(合計 100)。インストールシート上のアプリ内タイプミックスドーナツを駆動します。
duration_histogram 必須object持続時間ビンごとのワークアウト数: 0-3030-6060-9090+(分)。インストールシートの持続時間チャートを駆動します。
contents 必須arrayワークアウトごとの完全なエントリ — ライブラリマニフェストのエントリ形状のスーパーセット。各エントリは slugnameduration_seconds、サマリー指標、サムネイル描画用の sparkline 配列を持ちます。

ダウンロードした .ytwpack のインストール経路は 2 つあります:

サンプルパックマニフェスト(可読性のため contents を省略):

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

ライブラリとパックマニフェスト

ダウンロード可能なアーティファクトと一緒に 2 つのマニフェストが公開されています。どちらもプレーンな JSON であり、直接フェッチできる JSON Schema ドキュメントで記述されています。

URLリスト内容JSON Schema
library/manifest.json ライブラリ内のすべての厳選された .ytw — 閲覧 / 検索 / フィルタークライアント向けのワークアウトごとのメタデータ。利用可能な .ytwpack ダウンロード(ファイルパス、バージョン、コンテンツハッシュ、タイプミックスサマリー、アイコン URL)もリストします。 /schemas/workout-manifest.json
packs/manifest.json パックカタログエンドポイント: 公開されたすべての .ytwpack とサマリーメタデータ。ライブラリマニフェストの packs 配列と同じパックごとのエントリ形状で、アプリ内のパックライブラリはライダーが開始したリフレッシュ時にこれを取得します。 /schemas/workout-manifest.json
(各 .ytwpack 内部) アーカイブのルートに manifest.json として格納されたパックごとのマニフェスト — 上記の表がその形状を記述しています。 /schemas/workout-pack-manifest.json

ライブラリを利用するツール(カスタムワークアウトブラウザ、.zwo 形式に変換するワークアウトコンバーター、パックを表示するコーチダッシュボードなど)を作っている場合、これらが検証すべき契約です。両マニフェストの contents / workouts 配列には同じワークアウトごとのエントリ形状が現れるため、一方を扱えるクライアントはもう一方も扱えます。

実例

ランプインターバル

FTP の 40 % から 75 % まで線形補間でランプする 5 分間のウォームアップ:

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

オーバー・アンダー

FTP の 95 % で 2 分間 / FTP の 105 % で 1 分間を 3 セット、リピートグループとして表現:

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

心拍ゾーンワークアウト

中盤に 3 分間の Z4 サージを含む 30 分間の Z2 持久力ライド:

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

多言語対応

EN + DE + NL の strings ブロックを持つ最小限のスイートスポット例。同じワークアウト、3 つのネイティブ体験:

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

よくある落とし穴

リファレンス

プログラマチックなフォーマット仕様の検索(フィールド表、例、制約、用語集)について、機械可読の正規ソースは Your Trainer MCP です — 任意のMCPクライアントから get_format_specget_canonical_examplesget_format_constraints、または get_format_glossary を呼び出してください。これらのツールはこのページを駆動するのと同じナレッジレジストリから配信されます。ツールの回答がこのページと食い違った場合、MCPが正規であり、このページが古いと判断してください。

JSON Schema(これらの形式の上に構築するクライアント向けの機械可読契約):

← マニュアル&ガイドに戻る