ツーリングルート&装備自動提案ツール

.wrap{padding:1.5rem 0;max-width:680px;margin:0 auto} .header{display:flex;align-items:center;gap:10px;margin-bottom:1.5rem} .header i{font-size:24px} .header h2{font-size:18px;font-weight:500;margin:0} .header p{font-size:13px;color:#666;margin:0} .form-row{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:12px} .form-group{display:flex;flex-direction:column;gap:6px} .form-group label{font-size:13px;color:#666} .form-group input,.form-group select{padding:8px 12px;border:1px solid #ddd;border-radius:8px;font-size:14px;width:100%;box-sizing:border-box} .chip-group{display:flex;flex-wrap:wrap;gap:8px} .chip{padding:6px 14px;border-radius:20px;border:1px solid #ddd;font-size:13px;cursor:pointer;background:#fff;color:#666;transition:all 0.15s} .chip.active{background:#E6F1FB;border-color:#378ADD;color:#0C447C} .btn-gen{width:100%;padding:12px;font-size:15px;font-weight:500;background:#fff;border:1px solid #ddd;border-radius:12px;cursor:pointer;margin-top:1rem;display:flex;align-items:center;justify-content:center;gap:8px} .btn-gen:hover{background:#f5f5f5} .btn-gen:disabled{opacity:0.5;cursor:not-allowed} .result-card{margin-top:1.5rem;background:#fff;border:1px solid #eee;border-radius:12px;padding:1.25rem} .route-title{font-size:16px;font-weight:500;margin:0 0 4px} .route-meta{font-size:13px;color:#666;margin:0 0 1rem} .route-meta span{margin-right:14px} .tags-row{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:1rem} .tag{font-size:12px;padding:3px 10px;border-radius:20px;background:#FAEEDA;color:#633806} .waypoints{list-style:none;padding:0;margin:0 0 1.25rem} .waypoint{display:flex;align-items:flex-start;gap:10px;padding:10px 0;border-bottom:1px solid #eee} .waypoint:last-child{border-bottom:none} .wp-num{width:24px;height:24px;border-radius:50%;background:#E6F1FB;color:#0C447C;font-size:12px;font-weight:500;display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:1px} .wp-name{font-size:14px;font-weight:500;margin:0 0 2px} .wp-desc{font-size:13px;color:#666;margin:0} .tip-box{background:#EAF3DE;border-radius:8px;padding:10px 14px;font-size:13px;color:#3B6D11;margin-bottom:1.25rem} .gear-section{border-top:1px solid #eee;padding-top:1.25rem} .gear-title{font-size:15px;font-weight:500;margin:0 0 12px} .gear-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:10px} .gear-card{background:#f9f9f9;border-radius:8px;padding:12px} .gear-name{font-size:13px;font-weight:500;margin:0 0 4px} .gear-why{font-size:12px;color:#666;margin:0 0 8px} .gear-link{display:inline-flex;align-items:center;gap:4px;font-size:12px;color:#185FA5;text-decoration:none;border:1px solid #B5D4F4;border-radius:6px;padding:4px 10px;background:#E6F1FB} .loading{text-align:center;padding:2rem;color:#666;font-size:14px} .dot{display:inline-block;animation:blink 1.2s infinite} .dot:nth-child(2){animation-delay:.2s} .dot:nth-child(3){animation-delay:.4s} @keyframes blink{0%,80%,100%{opacity:0}40%{opacity:1}} .err{background:#FCEBEB;border-radius:8px;padding:10px 14px;font-size:13px;color:#A32D2D;margin-top:1rem} .affiliate-note{font-size:11px;color:#aaa;margin-top:1rem;text-align:center} .badge-must{font-size:11px;background:#FCEBEB;color:#A32D2D;padding:2px 7px;border-radius:10px;font-weight:400} .badge-rec{font-size:11px;background:#EAF3DE;color:#3B6D11;padding:2px 7px;border-radius:10px;font-weight:400}

🏍️ ツーリングルート+装備提案

エリアと条件を入れるだけ。ルートも装備もAIにお任せ

出発エリア
走行距離のめやす 100km前後(日帰り・軽め) 200〜300km(日帰りがっつり) 400km以上(泊まりも視野)
ルートの雰囲気(複数OK)
山岳・峠
海沿い
のんびり田園
グルメ・観光
ガチ走り
バイクタイプ
ネイキッド
スポーツ・SS
アドベンチャー
クルーザー
走る季節
// ★ここにアフィリエイトリンクを入れてください★ const AFFILIATE_LINKS = { “グローブ”: “https://ここにA8やRakutenのリンクを貼る”, “ヘルメット”: “https://ここにA8やRakutenのリンクを貼る”, “ジャケット”: “https://ここにA8やRakutenのリンクを貼る”, “レインウェア”: “https://ここにA8やRakutenのリンクを貼る”, “ブーツ”: “https://ここにA8やRakutenのリンクを貼る”, “タンクバッグ”: “https://ここにA8やRakutenのリンクを貼る”, “ナビ・スマホホルダー”: “https://ここにA8やRakutenのリンクを貼る”, “プロテクター”: “https://ここにA8やRakutenのリンクを貼る”, “インカム”: “https://ここにA8やRakutenのリンクを貼る”, “チェーンロック”: “https://ここにA8やRakutenのリンクを貼る” }; document.querySelectorAll(‘.chip’).forEach(c => { c.addEventListener(‘click’, () => { const group = c.closest(‘.chip-group’); if (group.id === ‘seasons’) { group.querySelectorAll(‘.chip’).forEach(x => x.classList.remove(‘active’)); } c.classList.toggle(‘active’); }); }); document.getElementById(‘genBtn’).addEventListener(‘click’, async () => { const area = document.getElementById(‘area’).value.trim(); if (!area) { alert(‘出発エリアを入力してください’); return; } const distance = document.getElementById(‘distance’).value; const vibes = […document.querySelectorAll(‘#vibes .chip.active’)].map(c => c.dataset.val).join(‘、’) || ‘こだわりなし’; const bike = […document.querySelectorAll(‘#bikes .chip.active’)].map(c => c.dataset.val).join(‘、’) || ‘指定なし’; const season = […document.querySelectorAll(‘#seasons .chip.active’)].map(c => c.dataset.val).join(”) || ‘指定なし’; const btn = document.getElementById(‘genBtn’); const out = document.getElementById(‘output’); btn.disabled = true; out.innerHTML = ‘
AIがルートと装備を考えています...
‘; const gearKeys = Object.keys(AFFILIATE_LINKS).join(‘、’); const prompt = `あなたはベテランツーリングライダーです。以下の条件でツーリングルートと装備リストを提案してください。\n\n出発エリア: ${area}\n走行距離: ${distance}\n雰囲気: ${vibes}\nバイク: ${bike}\n季節: ${season}\n\n以下のJSON形式のみで返してください(コードブロック記号・前後の説明文は不要):\n{\n “title”: “ルート名”,\n “distance”: “総距離”,\n “time”: “所要時間”,\n “level”: “初級者向け or 中級者向け or 上級者向け”,\n “highlights”: [“ハイライト1″,”ハイライト2″,”ハイライト3”],\n “waypoints”: [\n {“name”:”地点名”,”desc”:”見どころ1〜2文”},\n {“name”:”地点名”,”desc”:”説明”},\n {“name”:”地点名”,”desc”:”説明”},\n {“name”:”地点名”,”desc”:”説明”},\n {“name”:”地点名”,”desc”:”説明”}\n ],\n “tip”: “ワンポイントアドバイス”,\n “gear”: [\n {“name”:”アイテム名(必ず次の中から: ${gearKeys})”,”why”:”このルート・季節でなぜ必要か1文”,”priority”:”必須 or おすすめ”},\n {“name”:”アイテム名”,”why”:”理由”,”priority”:”必須 or おすすめ”},\n {“name”:”アイテム名”,”why”:”理由”,”priority”:”必須 or おすすめ”},\n {“name”:”アイテム名”,”why”:”理由”,”priority”:”必須 or おすすめ”},\n {“name”:”アイテム名”,”why”:”理由”,”priority”:”必須 or おすすめ”}\n ]\n}`; try { const res = await fetch(‘https://api.anthropic.com/v1/messages’, { method: ‘POST’, headers: {‘Content-Type’:’application/json’}, body: JSON.stringify({ model: ‘claude-sonnet-4-20250514′, max_tokens: 1500, messages: [{role:’user’, content: prompt}] }) }); const data = await res.json(); const text = data.content?.map(i => i.text||”).join(”).trim().replace(/“`json|“`/g,”).trim(); const r = JSON.parse(text); const gearHtml = r.gear.map(g => { const link = AFFILIATE_LINKS[g.name]; const isPriority = g.priority === ‘必須’; return `
${g.name} ${g.priority}
${g.why}
${link && !link.includes(‘ここに’) ? `楽天で見る` : ”}
`; }).join(”); out.innerHTML = `
${r.title}
📍 ${r.distance} ⏱ ${r.time} 🔥 ${r.level}
${r.highlights.map(h => `${h}`).join(”)}
    ${r.waypoints.map((wp,i) => `
  • ${i+1}
    ${wp.name}
    ${wp.desc}
  • `).join(”)}
💡 ${r.tip}
🎒 このルートにおすすめの装備
${gearHtml}
※商品リンクはアフィリエイトリンクを含みます
`; } catch(e) { out.innerHTML = ‘
生成に失敗しました。もう一度お試しください。
‘; } btn.disabled = false; });