Travel Guidebook Maker
調査から製本までをワンストップで行う旅行ガイドブック生成エンジン——AIイラストゼロ、絵文字ゼロ、純粋なCDN導入。Tabler Icons + インラインSVG装飾 + Claudeのデザイン美学により、温かみとデザイン性を兼ね備えた旅行ガイドPDFを作成します。
デザイン哲学
Monocleの編集センス + DKのビジュアルストーリーテリング + Lonely Planetの情報深度 + Claudeの温かい美学
これは冷たいナビゲーションマニュアルではなく、温かみのある旅行の相棒です——羊皮紙のような温かみのある背景に、セリフ体で目的地のストーリーを語り、アイコンシステムで機能情報をマークし、装飾要素で編集・出版の感覚を演出します。
核心理念:組版こそがデザイン。 AIによる画像生成や写真に依存せず、フォントの階層、機能色システム、インラインSVG装飾、CSS疑似要素によって、ガイドブック自体にデザイン性を持たせます。
全体フロー
Stage 0 環境準備 → Stage 1 要件確認
→ Stage 2 詳細調査 [5つのexplore agentを並列実行]
→ Stage 3 旅程設計
→ Stage 4 コンテンツ作成 [専任のgeneral-purpose agent]
→ Stage 5 HTML納品と確認 → Stage 6 PDFエクスポート
Stage 0でNode.js + Playwright環境を自動検出。Stage 2では並列調査で情報収集を高速化。Stage 4では専任エージェントがクリーンなコンテキストでHTMLを記述し、一貫性を確保。Stage 5はHTMLのチェックポイントで、ユーザーが確認・承認した後にStage 6でPDFをエクスポートします。
Stage 0: 環境準備
ガイドブック制作を開始する前に、PDFエクスポート環境が整っていることを確認します。
以下の順序で項目ごとにチェックし、いずれかのステップで失敗した場合は停止し、ユーザーに通知します。
1. Node.js
node --version
- ✅ v18.x 以上 → 続行
- ❌ コマンドが存在しない → 停止し、インストールを促す:https://nodejs.org/
2. package.json
ls package.json
- ✅ 存在する → 続行
- ❌ 存在しない →
npm init -y
3. Playwright
node -e "require('playwright')"
- ✅ エラーなし → 続行
- ❌ エラーあり →
npm install playwright && npx playwright install chromium
4. html2pdf.mjs
scripts/html2pdf.mjs にバンドルされており、Stage 6で作業ディレクトリにコピーされます。
5. 高德地図 MCP(オプション拡張)
高德 MCP ツールを呼び出し、利用可能性を検証します。
呼び出し maps_whether("{目的地都市}")
- ✅ 天気データが返ってくる →
AMAP_AVAILABLE = trueに設定 - ❌ ツールが存在しない、またはエラー →
AMAP_AVAILABLE = falseに設定
高德 MCP は拡張レイヤーです——利用できなくてもガイドブックは通常通り生成され、正確なデータのみがLLMによる推定にダウングレードされます。
ユーザーが設定していない場合の通知(1回のみ、フローをブロックしない):
"💡 高徳地図 MCP が設定されていないことを検出しました。ガイドブックは通常通り生成されますが、距離・交通・天気データは推定値を使用します。正確なデータが必要な場合は、MCP設定に
@amap/amap-maps-mcp-serverを追加してください。"
環境準備完了確認
すべてのチェックを通過したら、次のように出力します。
"✅ 環境準備完了(Node.js {バージョン} + Playwright + Chromium{高德利用可能時:+ 高德地図 MCP})。ガイドブックの作成を開始します。"
Stage 1: 要件確認
ユーザーに以下のパラメータを確認します(指示から推測できるものは質問せず、推測できないもののみ質問します)。
承知しました。旅行ガイドブックを作成します。以下の情報を確認させてください。
- ルート名:「{指示から推測}」でよろしいですか?
- 旅行タイプ:自驾游(ドライブ)/ 徒步(ハイキング)/ 城市漫游(街歩き)/ 混合(ミックス)?
- 対象読者:深度文化游(ディープな文化体験)/ 輕鬆休閒遊(リラックス&レジャー)/ 探検挑戦遊(探検&チャレンジ)?
- 総日数:{推測日数}日でよろしいですか?
- 個人情報:表紙や末尾に個人/チーム情報を追加しますか?
修正がある場合はそのままお知らせください。問題なければすぐに開始します。
ショートカットモード:ユーザーが十分な情報を提供している場合、確認をスキップして直接実行します。
デフォルト値:旅行タイプ=自驾游(ドライブ)、対象読者=深度文化游(ディープな文化体験)、日数=ルートから推測、個人情報=なし。
インテリジェントルーティング
要件確認後、ユーザーの入力に基づいて開始Stageを決定します。
| ユーザーが提供した内容 | ジャンプ先 | 説明 |
|---|---|---|
| 目的地/日数のみ | Stage 2 | 標準フルフロー |
| 既存の旅程ファイル(Markdown/テキスト) | Stage 3 | 旅程を読み込んで設計を抽出、調査をスキップ |
| 既存の旅程 + "確認済み/調査不要" | Stage 4 | 直接作成・組版に進む |
| 既存のHTMLガイドブック | Stage 5 | 直接チェックに進み、修正後にPDFエクスポート可能 |
判断基準:ユーザーが @ファイル名 参照を添付したか、「旅程は確認済み」、「調査は不要」などと明示したか。不確かな場合は、デフォルトで完全なフローを実行しますが、「調査を行いますか、それとも直接作成を開始しますか?」と積極的に尋ねます。
Stage 2: 詳細調査(並列Sub-Agent)
旅行ガイドブックの調査では、実用情報と文化的深みの両方をカバーする必要があります。並列explore agentを使用して調査を高速化します——各方向に独立したエージェントが同時に出発し、互いにブロックしません。
並列調査アーキテクチャ
メインエージェント explore agent プール(並列)
┌──────────┐ ┌─────────────────────────┐
│ 5+1 の │ ── background ──→│ research-transport │
│ agent │ ── background ──→│ research-attractions │
│ を構築 │ ── background ──→│ research-food │
│ │ ── background ──→│ research-culture │
│ │ ── background ──→│ research-practical │
│ │ ── background ──→│ research-spatial (高德) │
│ │ └─────────────────────────┘
│ 通知を待つ│ ←── 自動通知 ─── (各エージェント完了後)
│ 収集・統合│ ── read_agent ──→ 各エージェントの結果を取得
│ レポート出力│
└──────────┘
research-spatialはAMAP_AVAILABLE = trueの場合のみ起動します。利用できない場合は5つのエージェントのみ起動します。
エージェントの役割分担
task ツールを使用し、agent_type: "explore"、mode: "background" で、5+1 個のエージェントを同時に起動します。
| エージェント名 | 調査方向 | 検索キーワード例(中英混合) |
|---|---|---|
research-transport | 交通ルート | "{出発地}から{目的地}へ 高速鉄道/ドライブ 時刻 料金", "{destination} transport" |
research-attractions | コア観光スポット | "{目的地} 必見スポット 入場料 営業時間 TOP10", "{destination} attractions" |
research-food | 現地グルメ | "{目的地} 名物料理 おすすめレストラン グルメストリート 一人当たり料金", "{destination} local food" |
research-culture | 文化・歴史 | "{目的地} 歴史 文化 逸話 民俗 方言", "{destination} history culture" |
research-practical | 実用情報 | "{目的地} {月} 天気 予算 安全 注意事項", "{destination} travel tips" |
自驾游(ドライブ)の場合は、7つ目のエージェント
research-road(道路状況、ガソリンスタンド、標高変化)を追加します。
高德空間データエージェント(AMAP_AVAILABLE = true 時)
6つ目のエージェント research-spatial は、高徳地図データの収集を専門に行います。
あなたは空間データ収集担当者です。高徳地図 MCP ツールを使用して以下のデータを収集してください。
目的地:{目的地}
既知の観光スポットリスト:{要件確認から抽出したすべての観光スポット名}
## タスク 1: 観光スポット POI データ
各観光スポットに対して maps_text_search("{観光スポット名}") を呼び出し、以下を抽出します。
- POI ID, 名称, 完全な住所, 緯度経度, 評価, 営業時間, 電話番号
## タスク 2: 周辺発見
各コア観光スポット(毎日の主要スポット)に対して maps_around_search を呼び出します。
- キーワード="レストラン|軽食", location={観光スポット座標}, radius=1000 → 周辺レストラントップ5
- キーワード="コンビニ|薬局", location={観光スポット座標}, radius=500 → 緊急施設
## タスク 3: 天気予報
maps_whether("{目的地都市名または adcode}")
## タスク 4: 地理コーディング
すべての地名に対して maps_gep を呼び出し、正確な座標を取得します。Stage 3のルート計画で使用します。
## 出力形式
### 観光スポット POI サマリー
| 観光スポット | 住所 | 緯度経度 | 評価 | 営業時間 |
|------|------|--------|------|---------|
| ... | ... | ... | ... | ... |
### 周辺発見
#### {観光スポット名} 周辺
| 名称 | タイプ | 距離 | 評価 |
|------|------|------|------|
| ... | ... | ... | ... |
### 天気予報
| 日付 | 天気 | 気温 | 風力 |
|------|------|------|------|
| ... | ... | ... | ... |
自驾游(ドライブ)の場合は、6つ目のエージェント
research-road(道路状況、ガソリンスタンド、標高変化)を追加します。
エージェントプロンプトテンプレート
各エージェントのプロンプトは以下の構造に従います。
あなたは旅行調査担当者です。【{方向}】の調査を担当します。
## タスクパラメータ
- 目的地:{目的地}
- 出発地:{出発地}
- 日付:{具体的な日付}
- 日数:{N} 日
- 旅行タイプ:{ドライブ/高速鉄道/混合}
## 調査要件
1. bash を使用して curl または web_fetch を実行し、以下のURLを取得します(1つずつ試し、失敗したらスキップ)。
- {事前設定されたURLリスト、3-5個の関連ウェブサイト}
2. 各情報源から重要なデータポイントを抽出します。
3. すべてのURLが失敗した場合、既存の知識に基づいて整理し、「⚠️ モデル知識」と注釈を付けます。
## 出力形式(厳守)
### {方向名}
#### コア発見
- 発見1:{具体的なデータ}(出典:{URL})
- 発見2:...
#### おすすめリスト
| 名称 | 詳細 | 料金 | 備考 |
|------|------|------|------|
| ... | ... | ... | ... |
#### 情報源
- {URL1}
- {URL2}
#### データの鮮度
- 上記情報は {現在の日付} に取得したものです。出発前に料金や営業時間を再確認することをお勧めします。
結果の収集とマージ
すべてのエージェントが完了したら、次の手順を実行します。
- 各エージェントから
read_agentで結果を取得します。 - 統一された調査レポートにマージし、方向ごとに章立てします。
- 各データポイントの出典(URLまたは「モデル知識」)を明記します。
- いずれかのエージェントが失敗した場合、メインエージェントがその方向のLLM知識で補完します。
ダウングレード戦略
| シナリオ | 処理方法 |
|---|---|
| task ツールが利用不可 | 直列モードに戻る:メインエージェントが方向ごとに web_fetch を実行 |
| 一部のエージェントがタイムアウト/失敗 | メインエージェントがLLM知識で失敗した方向を補完 |
| research-spatial が失敗 | 距離/時間はLLMで推定し、「約」の接頭辞を付ける |
| 完全にネットワーク不可 | オフラインモード:すべてLLM知識に基づき、「⚠️ 出発前にご確認ください」と注釈 |
調査品質要件
- 並列モード:各エージェントが少なくとも3つの有効な情報源、合計で15以上
- 直列モード:情報源の総数が20以上(3日以内の短距離旅行:10以上)
- オフラインモード:可能な限り豊富に、データの鮮度が不確かなことを注釈
- 優先順位:公式観光サイト、経験豊富な旅行ブロガー、現地メディア、専門フォーラム
- 料金情報は鮮度を明記
- 重要な事実は少なくとも2つの独立した情報源で相互検証
Stage 3: 旅程設計
調査結果に基づいて、1日の旅程の骨組みを生成します。高徳空間データが利用可能な場合は、実際のルート計画をLLM推定の代わりに使用します。
高德ルート計画(AMAP_AVAILABLE = true 時)
Stage 2の research-spatial エージェントがすべての観光スポットの正確な座標を提供しています。これに基づき、メインエージェントが高德ルート計画APIを呼び出します。
1日の旅程内の連続する観光スポットペアに対して、旅行タイプに応じてAPIを選択します。
旅行タイプ │ API │ 説明
──────────┼──────────────────────────────────────┼──────────
自驾游(ドライブ)│ maps_direction_driving(A座標, B座標) │ 距離/時間/通行料
城市漫游(街歩き)│ maps_direction_walking (≤3km) │ 徒歩距離/時間
│ maps_direction_transit_integrated (>3km)│ 地下鉄/バス案内
サイクリング │ maps_bicycling │ 自転車ルート/距離
都市間移動 │ maps_direction_transit_integrated │ 電車/バス案内
すべてのモード │ maps_distance │ 1日の総距離検証
高德が利用できない場合は、LLM知識を使用して距離と時間を推定し、ガイドブックでは「約」の接頭辞を付けて示します。
Stage 3.1: 旅程実行可能性ゲート(Feasibility Gate)
第一原理:旅程とは、物理的制約下での計画であり、観光スポットの自由な組み合わせではありません。 1日の旅程を書き込む前に、以下の検証を通過する必要があります——通過しない場合は、強制的に分割するか、観光スポットを削除します。
ルール一:日帰り往復実行可能性の公式
利用可能総時間 = 出発時間から帰着時間まで(通常12h、高原地域は10h)
検証公式:
出発地 → 観光スポットA(片道時間)× 2 ← 往復交通
+ 各観光スポットの滞在時間の合計
+ 観光スポット間の交通時間の合計
+ バッファ時間(1h)
≤ 利用可能総時間
条件を満たさない → 複数日に分割 または 最も遠い観光スポットを削除
計算ツール(優先度順):
- AMAP_AVAILABLE = true →
maps_direction_driving/maps_distanceを呼び出し、実際の所要時間を取得 - AMAP_AVAILABLE = false → LLM知識で推定し、ガイドブックに「約」と注釈
ルール二:都市間観光スポットの強制分離
| 出発地からの片道距離 | 強制ルール |
|---|---|
| ≤ 80km | 他の観光スポットと同じ日に可能 |
| 80–150km | 同日にはこの観光スポットのみ、他の目的地は不可 |
| > 150km | 強制的に独立した1日とするか、途中に宿泊を計画 |
典型的な落とし穴:ラサ出発、ヤムドロク湖(羊卓雍錯)(100km)は日帰り可能;シガツェのタシルンポ寺/パルコル寺(280km)は絶対にラサの観光スポットやヤムドロク湖と同じ日に組み込んではいけません。
ルール三:特別な目的地の制約
高原地域(標高3500m以上):
| 到着後の日数 | 許可される活動範囲 | 禁止 |
|---|---|---|
| Day 1 | ホテル周辺の散歩、≤1h | 一切の観光地への入場 |
| Day 2 | 市内の平坦な観光スポット、≤3h | 標高4000m以上の観光スポット |
| Day 3+ | 通常の市内観光 | 標高4500m以上はDay 4以降を推奨 |
| Day 4+ | 高所への訪問可能(ヤムドロク湖 4441m) | — |
| Day 5+ | 非常に高所への挑戦可能(ナムツォ湖 4718m) | 酸素ボンベを携帯のこと |
強制執行:高原旅程のDay 1に有料の観光スポットを入れてはなりません。違反した場合、自動的にその観光スポットを1日後ろにずらします。
ルール四:生成後のレビューチェックリスト
1日の旅程の下書きが生成されたら、1つずつ検証する必要があります。
□ 当日の総走行距離(往復)は実行可能範囲内か?
□ すべての観光スポットは同じ合理的なエリア内にあるか?(複数の都市にまたがっていないか)
□ 暗黙の「長距離ジャンプ」は含まれていないか?(例:A→B→Cが一見近いが、実際には遠回り)
□ 高原行程:高度順応ルールに違反していないか?
□ チャーター/ドライブを含む日帰り旅行:十分な観光/滞在時間(≥2h)があるか?
□ 帰路の時間は十分に確保されているか?(日没前に戻れるか)
いずれかの項目を満たさない場合 → 赤色警告、該当日の旅程を再計画しなければStage 4に進めません。
リズム設計
- 緩急のバランス:長距離運転日 + 深掘り観光日を交互に配置
- クライマックス設計:最も魅力のある目的地を旅程の中盤(Day 3-5)に配置
- バッファ時間:3-4日ごとに「自由日」または「休息日」を設定
- 感情曲線:出発の興奮 → 順応期 → クライマックス → 余韻 → 別れの惜しさ
1日の旅程構造
Day X: [出発地] → [目的地]
├─ 走行距離:XXkm(高德実測 / LLM推定)
├─ 予定時間:Xh(観光時間を含む)
├─ 交通手段(高德利用可能時):
│ ├─ 観光スポットA→観光スポットB:徒歩 12分 / 0.9km
│ ├─ 観光スポットB→観光スポットC:地下鉄2号線 3駅 / 15分
│ └─ 観光スポットC→ホテル:バス537路 / 25分
├─ 天気(高德利用可能時):☁️ 曇り 26°C
├─ 今日のハイライト:一言で要約
├─ 必見スポット:2-3 選抜(高德評価を含む)
├─ 周辺発見(高德利用可能時):観光スポット周辺の高評価レストラン/カフェ
├─ グルメおすすめ:1-2 個
├─ 宿泊おすすめ:1-2 個
└─ ヒント:天気に関するアドバイス + 実際の交通アドバイスを含む
「高德利用可能時」と記載されたフィールドは、
AMAP_AVAILABLE = falseの場合、省略するかLLM推定で代替します。
ユーザー確認
旅程の骨組みを表示し、確認または修正を求めます。確認後、Stage 4に進みます。
ショートカットモード:ユーザーが「確認不要で直接書いて」と要求した場合はスキップします。
Stage 4: コンテンツ作成と組版
これはガイドブックの中核となる段階です——調査結果と設計を、デザイン性の高いHTMLガイドブックに変換します。
実行モードの選択
利用可能なツールに基づいて、最適なモードを自動選択します。
| 条件 | モード | 説明 |
|---|---|---|
| task ツール利用可能 | 専任エージェントモード(推奨) | 1つのgeneral-purpose agentを起動し、クリーンなコンテキストですべてのHTMLを作成 |
| task 利用不可 | メインエージェント直接作成モード | メインエージェントがheredocを使用してバッチ書き込み(従来の方法) |
専任エージェントモード(推奨)
中核的な利点:HTML作成エージェントはクリーンなコンテキストを持ちます——調査プロセス、履歴会話、ルート議論のノイズが含まれません。最初の行から最後の行まで、スタイルが完全に統一されます。
1つの general-purpose agent(mode: "background")を起動し、以下の内容を完全にpromptに渡します。
あなたは旅行ガイドブックHTML作成の専門家です。完全な単一ファイルのHTMLガイドブックを生成してください。
## ガイドブックパラメータ
- ルート名:{名称}
- ファイル名:{名称}_guidebook.html
- 旅行日:{日付}
- 日数:{N} 日
- 旅行タイプ:{タイプ}
## CSS仕様(references/layout-css.mdの内容を完全にコピー)
{layout-css.md 全文}
## 章テンプレート(references/chapter-templates.mdの内容を完全にコピー)
{chapter-templates.md 全文}
## 調査データ(Stage 2 統合レポート)
{調査レポート全文}
## 旅程設計(Stage 3 確認版)
{1日の旅程設計}
## 作成スタイル
3層のニーズ駆動:
- 方向性(Where)——正確かつ明確:地名、方向、距離、時間を正確に
- 意思決定(What)——ユーザーに代わって選別:1日あたり2-3の必見スポット
- 感情(Why)——意味を付与:歴史的なストーリーや地元の人々の視点を取り入れる
## 技術要件
1. heredocを使用してバッチ書き込み(最初は cat >、以降は cat >>)、シングルクォート << 'HTMLEOF'
2. ¥ は ¥、— は —、→ は →、° は ° に置き換え
3. 各バッチ書き込み後に wc -c でファイルサイズの増加を確認
4. 総バッチ数は3-5、論理的な段落で分割
5. すべてのCSSは <style> にインライン、すべてのSVGはインライン、外部画像はゼロ
6. 最終バッチには必ず </body></html> のクロージングタグを含める
メインエージェントは待機中:他の軽量な作業を行うか、ユーザーに「HTMLを生成中です。約2-3分かかります。」と通知します。
エージェント完了後:
read_agentで結果を取得し、HTMLファイルが生成されたことを確認wc -cでファイルサイズを検証(5日間の旅程で50-80KB程度)- Stage 5へ
メインエージェント直接作成モード(ダウングレード)
task ツールが利用できない場合、メインエージェントが直接 heredoc を使用してバッチ書き込みを行います。
章構成
ガイドブックは5部構成です。各章の完全なHTMLテンプレートについては references/chapter-templates.md を参照してください。
- 出発前:表紙 / 旅程概要 / 出発準備
- 毎日の旅程:Day-by-Day(中核)——スケジュールカード、ルート説明、必見スポット、グルメ、宿泊、ヒント、メモ欄
- 目的地深掘り:2-3の重要な目的地の詳細な紹介
- 実用付録:緊急連絡先、よく使う言葉、費用明細、おすすめプレイリスト
- 裏表紙:旅の言葉 + 個人情報 + 旅の感想スペース
組版仕様
ガイドブックのビジュアルデザインは、Claudeの暖色系の美学を継承しています。完全なCSS仕様については references/layout-css.md を参照してください。以下の内容を含みます。
- 外部リソース(Google Fonts + Tabler Icons CDNのみ)
- ページレイアウト(A4, max-width 680px)
- フォントシステム(Noto Serif SC / Noto Sans SC / JetBrains Mono)
- カラースキーム(Parchment 羊皮紙背景 + Terracotta テラコッタ色 + 機能色システム)
- 装飾要素(コンパス、区切り線、DAYバッジ、カードコーナー飾り、ドロップキャップ)
- 改ページ制御(表紙は独立、Dayは新しいページ、カードは分割しない)
- 印刷対応(暖色系の背景を保持)
作成スタイル
3層のニーズ駆動ライティング:
- 方向性(Where)——正確かつ明確:地名、方向、距離、時間は正確でなければならず、身体的な感覚に基づく説明(「左手側」、「前方200メートル」)を使用
- 意思決定(What)——ユーザーに代わって選別:各目的地では2-3の必見スポットのみを推奨し、「必見/任意/時間があれば行ける」の優先度をマーク
- 感情(Why)——意味を付与:各場所で「なぜ訪れる価値があるのか」を語り、歴史的なストーリーや地元の人々の視点を取り入れ、文学的な表現で風景を描写
感情強調ライティング(高徳データ駆動)
高德空間データが利用可能な場合、以下の4つの感情強調モードを適用します。
1. 距離のナラティブ——正確な距離を知覚可能な体験に変換:
- ≤500m → 「数分の距離」 + 途中で見える/匂う/聞こえるもの
- 500m-2km → 「散歩する距離」 + 道中の風景描写
-
2km → 交通アドバイス + 車窓からの風景
- 例:「黄鶴楼の南門を出て左折し、武珞路に沿って600メートル——およそ一曲分の時間——歩くと、户部巷に着きます。」
2. 周辺のサプライズ——高德が発見した高評価のPOI(LLMが知らないかもしれない新しい店/小さな店)を表示:
- 「💡 旅の発見」カードで表示
- 内容:名称、距離、評価、おすすめ理由の一言
3. 時間の知覚——天気 + 距離 + 時間帯 = 具体的な体験提案:
- 例:「本日26°C、曇り——長江大橋を歩くのに最適な天気です。橋の長さは1.6km、ゆっくり歩いて約22分。16:00に出発し、橋の中央に着く頃にちょうど夕日が見られます。」
4. 安心感——毎日のヒントに周辺の便利施設を組み込む:
- 例:「今夜の宿泊先から200m以内にファミリーマート(24h)があり、最寄りの薬局は400m先の武珞路にあります。」
高德が利用できない場合、これら4つのモードは自動的に省略されます——ガイドブックには完全な文化ナラティブとLLM推定データが残ります。
HTML生成(heredoc バッチ戦略)
完全な単一HTMLファイルを生成し、すべてのCSSは <style> にインライン、すべてのSVG装飾はインライン、外部画像はゼロです。
以下のheredoc戦略は、専任エージェントの内部実行とメインエージェント直接作成ダウングレードモードの両方に適用されます。
大ファイル書き込み戦略
ガイドブックHTMLは通常50-80KB(5日間の旅程で約30ページ)であり、write/createツールの1回あたりの上限を超える可能性があります。heredocを使用したバッチ追加戦略を採用します。
# 第1バッチ:HTML head + 完全なCSS(<style> タグ)
cat > {ファイル名}_guidebook.html << 'HTMLEOF'
<!DOCTYPE html>
<html lang="ja">
<head>...</head>
<style>/* すべてのCSS、references/layout-css.mdを参照 */</style>
<body>
HTMLEOF
# 第2バッチ:表紙 + 概要 + 出発準備
cat >> {ファイル名}_guidebook.html << 'HTMLEOF'
<div class="cover">...</div>
<div class="overview">...</div>
<div class="preparation">...</div>
HTMLEOF
# 第3-Nバッチ:毎日の旅程(1日ごと、または2日ごと)
cat >> {ファイル名}_guidebook.html << 'HTMLEOF'
<div class="day-chapter">...</div>
HTMLEOF
# 最終バッチ:深掘り + 付録 + 裏表紙 + クロージングタグ
cat >> {ファイル名}_guidebook.html << 'HTMLEOF'
<div class="deep-dive">...</div>
<div class="appendix">...</div>
<div class="back-cover">...</div>
</body></html>
HTMLEOF
重要な注意点:
- シングルクォートのheredoc(
<< 'HTMLEOF')を使用して、シェル変数の展開を防止 ¥記号はheredoc内では¥に置き換え、エンコーディング問題を回避- 各バッチ書き込み後に
wc -cでファイルサイズが正常に増加していることを確認 - 総バッチ数は3-5に制御し、論理的な段落で分割(HTMLタグの途中で分割しない)
Stage 5: HTML納品と確認
納品内容
- HTMLファイル:
{ルート名}_guidebook.html(単一ファイル、外部依存ゼロ) - 作業報告書:作成プロセスの記録(テンプレートは
references/report-template.mdを参照)
HTMLチェックポイント
HTMLが完了したら、まずユーザーにチェックしてもらい、直接PDFに進んではいけません。
"HTMLガイドブックを生成しました:
{ファイル名}_guidebook.html。ブラウザで開いて内容とレイアウトをご確認ください。ご確認後、お知らせいただければPDFをエクスポートします。修正が必要な場合は、どこをどのように変更するかをお知らせください。"
- ユーザーが「OK / 満足 / PDFをエクスポート」と言った → Stage 6へ
- ユーザーが「xxxを修正」と言った → 修正のためにStage 4に戻り、再度チェックを促す
Stage 6: PDFエクスポート
ユーザーがStage 5でHTMLに満足したことを確認した後にのみ実行します。
実行手順
1. エクスポートスクリプトの準備
作業ディレクトリに html2pdf.mjs があることを確認します。以下のように検索します。
# 最初にカレントディレクトリをチェック
ls html2pdf.mjs 2>/dev/null || \
# skillディレクトリ内のバンドルされたスクリプトを検索
find ~/.agents/skills/travel-guidebook -name "html2pdf.mjs" 2>/dev/null | head -1 | xargs -I{} cp {} ./html2pdf.mjs || \
find . -path "*/travel-guidebook/scripts/html2pdf.mjs" 2>/dev/null | head -1 | xargs -I{} cp {} ./html2pdf.mjs
それでも見つからない場合は、以下の最小スクリプトで作成します。
// html2pdf.mjs — Playwright A4 PDF export
import { chromium } from 'playwright';
import { resolve } from 'path';
const html = resolve(process.argv[2]);
const pdf = html.replace(/\.html$/, '.pdf');
const b = await chromium.launch();
const p = await b.newPage();
await p.goto('file://' + html, { waitUntil: 'networkidle' });
await p.waitForTimeout(2000);
await p.pdf({ path: pdf, format: 'A4', margin: { top: '2cm', right: '1.8cm', bottom: '2.5cm', left: '1.8cm' }, printBackground: true });
await b.close();
console.log('PDF saved:', pdf);
2. エクスポートの実行
node html2pdf.mjs {ファイル名}_guidebook.html
3. 検証と納品
PDFが存在することを確認し、サイズを表示して、ユーザーに開いて確認するよう促します。
"✅ PDFガイドブックをエクスポートしました:
{ファイル名}_guidebook.pdf({ページ数}ページ、{ファイルサイズ})。"
PDFパラメータ
| パラメータ | 値 | 説明 |
|---|---|---|
| 用紙 | A4 | 標準印刷サイズ |
| 上マージン | 2cm | |
| 下マージン | 2.5cm | ページ番号のスペース確保 |
| 左右マージン | 1.8cm | |
| フッター | 中央揃えのページ番号 | 9pt JetBrains Mono |
| 待機戦略 | networkidle + 2s | CDNリソースの読み込みを確実に |
| 背景 | printBackground: true | 羊皮紙の暖色テクスチャーを保持 |
代替案
Playwrightが失敗した場合は、ブラウザの手動印刷を案内します。Chrome/EdgeでHTMLを開く → Cmd/Ctrl+P → PDFとして保存
…
[truncated for translation]