WHYを5回繰り返すことで核心をみつける。
これってよく聞く話なんだけど、これをなんどもやれるように簡単なプログラムにしてみました。
Why × 5
コアに迫るためのツールだ。
Why1〜5 を順に入力 → 「まとめて出力」。ログ保存・コピー可能にしました。
Why ×5 — なぜを重ねて核心を探す
アプリの特徴
このミニアプリは、以下の機能を備えています。
- テーマ入力
解決したい問題や現象を1行で入力。 - Why入力 ×5
「なぜ?」を順に書いていける欄を用意。Enter… 改行Ctrl/⌘ + Enter… 次の欄へ
- まとめて出力
入力したWhyの流れをMarkdown形式に整形して一括表示。 - コピー機能(多段フォールバック付き)
- 通常:ワンクリックでクリップボードにコピー
- ブラウザ制限時:自動で選択/手動コピー用モーダルが出る
- ログ保存
ローカルストレージに保存 → 過去のWhy×5を一覧表示し、読み込み・再編集も可能。 - プリセット例
- マーケティング(LPのCVR改善など)
- プロダクト(継続率低下など)
- 学習(習慣化できないなど)
ワンクリックでサンプルを呼び出し、操作感をすぐ体験可能。
使い方(ステップごとに解説)
- テーマを書く
例:「新規登録が伸びない」 - Why 1〜5を入力
- Why1:直接の原因
- Why2:その原因の理由
- Why3〜5:さらに深掘り
👉 最後は「根本原因の仮説」が見える
- まとめて出力
- Markdown形式で一括整理
- 「次の一手(仮説・実験・KPI)」も自動提案される
- 保存 & コピー
- 保存:端末に残せるので、翌日や会議でも活用
- コピー:ブログ記事やノートに貼り付けて共有可能
活用シーン
- マーケティング戦略
- LPのCVRが伸びない → Why ×5で根本原因を洗い出す
- プロダクト開発
- 継続率が下がっている → ユーザー体験の阻害要因を掘り下げる
- 学習や自己改善
- 習慣が続かない → 行動単位や環境設計に原因があることを特定
まとめ
「Why ×5 ミニアプリ」は、
👉 問いを量産し、磨き、記録として残せるシンプルな習慣ツール です。
付箋やノートに書くだけでは続かないフレームワークも、Webアプリにすると自然にログが貯まり、「問いの質」を日々磨けるようになります。
Why ×5 — 思考を「検証プラン」に変換する v1.5
手順:テーマ → Why1〜5+タグ → 反証条件(If/Then) → 根本仮説 → SMART → 出力/保存/コピー
15:00
入力後にまとめて出力できます。
※空ならWhy5を用いて自動で流し込みます。
📒 ログ(デバイス内に保存)
📝 出力フォーマット見本(Markdown)
# テーマ
- {{topic}}
## Why ×5(タグ付き)
1. {{w1}} — [{{t1}}]
2. {{w2}} — [{{t2}}]
3. {{w3}} — [{{t3}}]
4. {{w4}} — [{{t4}}]
5. {{w5}} — [{{t5}}]
## 反証条件(If / Then)
- IF {{if1}} THEN {{then1}}
- IF {{if2}} THEN {{then2}}
## 根本仮説(検証可能)
- {{hypothesis}}
## 次の一手(SMART)
- 行動:{{act}}
- 計測:{{metric}}
- 期間:{{period}}週間(〜{{deadline}})
- 成功基準:{{success}}
THEN
`;
wrap.querySelector('.btn-del').onclick = ()=> wrap.remove();
ifthenList.appendChild(wrap);
}
addIfThen('奄美や長野で悪化した人が多い','水は原因ではない可能性');
addIfThen('食生活の変化が大きい','水以外の要因が主要因');
/* 入力で出力更新 */
[el.topic, el.w1, el.w2, el.w3, el.w4, el.w5, el.t1, el.t2, el.t3, el.t4, el.t5, hypoEl, actEl, metricEl, periodEl, successEl].forEach(n=> n.addEventListener('input', gen));
/* キー遷移(Enter/⌘Enter) */
const seq=[el.w1,el.w2,el.w3,el.w4,el.w5,hypoEl,actEl,metricEl,periodEl,successEl];
[el.topic, el.w1, el.w2, el.w3, el.w4, el.w5, hypoEl, actEl, metricEl, periodEl].forEach((node,i)=>{
node.addEventListener('keydown',e=>{
const isInput = node.tagName==='INPUT';
const next = ()=> seq[i+1]?.focus();
if(isInput && e.key==='Enter' && !e.shiftKey){ e.preventDefault(); next(); }
if(!isInput && e.key==='Enter' && (e.ctrlKey||e.metaKey)){ e.preventDefault(); next(); }
});
});
function sanitize(s){ return (s||'').toString().trim() }
function deadlineFromWeeks(w){ const d=new Date(); d.setDate(d.getDate()+(Number(w)||0)*7); return d.toLocaleDateString(); }
function val(){
const conds=[...ifthenList.querySelectorAll('.ifthen')].map(r=>({ if:sanitize(r.querySelector('.ifv').value), then:sanitize(r.querySelector('.thenv').value) })).filter(x=>x.if||x.then);
return {
topic:sanitize(el.topic.value),
w1:sanitize(el.w1.value), w2:sanitize(el.w2.value), w3:sanitize(el.w3.value), w4:sanitize(el.w4.value), w5:sanitize(el.w5.value),
t1:el.t1.value, t2:el.t2.value, t3:el.t3.value, t4:el.t4.value, t5:el.t5.value,
hypothesis: sanitize(hypoEl.value) || sanitize(el.w5.value),
act:sanitize(actEl.value), metric:sanitize(metricEl.value), period:sanitize(periodEl.value), success:sanitize(successEl.value),
conds
};
}
function md(v){
const dl=deadlineFromWeeks(v.period||0);
const why=[
`1. ${v.w1||'-'} — [${v.t1||'-'}]`,
`2. ${v.w2||'-'} — [${v.t2||'-'}]`,
`3. ${v.w3||'-'} — [${v.t3||'-'}]`,
`4. ${v.w4||'-'} — [${v.t4||'-'}]`,
`5. ${v.w5||'-'} — [${v.t5||'-'}]`,
].join('\n');
const ifthen=(v.conds.length? v.conds:[{if:'-',then:'-'}]).map(c=>`- IF ${c.if||'-'} THEN ${c.then||'-'}`).join('\n');
return [
`# テーマ
- ${v.topic||'-'}
## Why ×5(タグ付き)
${why}
## 反証条件(If / Then)
${ifthen}
## 根本仮説(検証可能)
- ${v.hypothesis||'-'}
## 次の一手(SMART)
- 行動:${v.act||'-'}
- 計測:${v.metric||'-'}
- 期間:${v.period? v.period+'週間':'-'}(〜${v.period? dl:'-'})
- 成功基準:${v.success||'-'}`
].join('\n');
}
function gen(){ el.out.textContent = md(val()); }
/* コピー */
async function copyText(text){
if(navigator.clipboard && window.isSecureContext){
try{ await navigator.clipboard.writeText(text); dialogCopy('コピー成功'); return; }catch(e){}
}
try{
const ta=document.createElement('textarea'); ta.value=text; ta.setAttribute('readonly','');
ta.style.position='fixed'; ta.style.top='-1000px'; ta.style.opacity='0';
document.body.appendChild(ta); ta.focus(); ta.select();
const ok=document.execCommand('copy'); document.body.removeChild(ta);
if(ok){ dialogCopy('コピー成功'); return; }
}catch(e){}
showCopyModal(text); dialogCopy('この環境では手動コピーのみ対応');
}
function showCopyModal(text){
el.copyTextArea.value=text; el.copyModal.style.display='flex';
el.copyModal.setAttribute('aria-hidden','false'); el.copyTextArea.focus(); el.copyTextArea.select();
}
$('#why5-copy-select').addEventListener('click',()=>{ el.copyTextArea.focus(); el.copyTextArea.select(); });
$('#why5-copy-close').addEventListener('click',()=>{ el.copyModal.style.display='none'; el.copyModal.setAttribute('aria-hidden','true'); });
function dialogCopy(msg){
let n=$('#copy-result'); if(!n){ n=document.createElement('div'); n.id='copy-result'; n.className='hint'; el.out.insertAdjacentElement('afterend', n); }
n.textContent=msg; const aria=$('#copy-aria'); if(aria) aria.textContent=msg;
}
/* バリデーション(視認性向けにメッセージ簡潔化) */
function toast(msg){
let t=$('#why5-toast');
if(!t){ t=document.createElement('div'); t.id='why5-toast'; t.setAttribute('role','status');
t.style.cssText='position:fixed;left:50%;bottom:18px;transform:translateX(-50%);background:var(--panel);border:2px solid var(--border);color:var(--text);padding:12px 16px;border-radius:12px;z-index:9999;box-shadow:0 8px 20px rgba(2,8,23,.12);font-weight:800';
document.body.appendChild(t);
}
t.textContent=msg; t.style.opacity='1'; clearTimeout(t._to); t._to=setTimeout(()=>{ t.style.opacity='0'; }, 2000);
}
function guard(){
const v=val();
if(!v.topic){ toast('テーマは必須'); return false; }
if(!v.w5){ toast('Why5(根本仮説)は必須'); return false; }
if(!v.hypothesis){ toast('根本仮説(一文)は必須'); return false; }
if(v.conds.length===0 || !v.conds[0].if || !v.conds[0].then){ toast('反証条件(If/Then)を1件以上'); return false; }
return true;
}
/* 保存(localStorage + Cookie反映) */
const KEY='why5.logs.v1.3';
function readLogs(){ try{ return JSON.parse(localStorage.getItem(KEY)||'[]'); }catch(e){ return [] } }
function writeLogs(arr){ localStorage.setItem(KEY, JSON.stringify(arr)) }
function pruneIfTooLarge(arr){
try{ localStorage.setItem('__quota_test__','1'); localStorage.removeItem('__quota_test__'); return arr; }
catch(e){ while(arr.length){ arr.pop(); try{ localStorage.setItem('__quota_test__','1'); localStorage.removeItem('__quota_test__'); break; }catch(_){}} return arr; }
}
function renderLogs(){
const logs=readLogs(); el.loglist.innerHTML='';
if(!logs.length){ el.loglist.innerHTML='保存はまだありません。
'; return }
logs.slice(0,50).forEach(it=>{
const row=document.createElement('div'); row.className='logitem';
row.innerHTML = `${escapeHtml(it.topic||'(無題)')}
`;
const act=document.createElement('div'); act.className='actions';
const loadB=btn('読み込む','secondary',()=>{ load(it); });
const copyB=btn('コピー','warn',async ()=>{ await copyText(md(it)); });
const delB=btn('削除','ghost',()=>{ del(it.id) });
act.append(loadB,copyB,delB); row.appendChild(act); el.loglist.appendChild(row);
});
}
function btn(label, cls, on){ const b=document.createElement('button'); b.textContent=label; if(cls) b.classList.add(cls); b.type='button'; b.onclick=on; return b }
function load(it){
el.topic.value=it.topic||'';
[el.w1,el.w2,el.w3,el.w4,el.w5].forEach((n,i)=> n.value=[it.w1,it.w2,it.w3,it.w4,it.w5][i]||'');
[el.t1,el.t2,el.t3,el.t4,el.t5].forEach((n,i)=>{ [...n.options].forEach(o=>o.selected=(o.text===([it.t1,it.t2,it.t3,it.t4,it.t5][i]||'仮説'))); });
hypoEl.value = it.hypothesis||''; actEl.value = it.act||''; metricEl.value=it.metric||''; periodEl.value=it.period||''; successEl.value=it.success||'';
ifthenList.innerHTML=''; (it.conds||[]).forEach(c=> addIfThen(c.if,c.then));
if(!it.conds || !it.conds.length) { addIfThen(); }
gen(); toast('読み込み完了');
}
function del(id){ const logs=readLogs().filter(x=>x.id!==id); writeLogs(logs); renderLogs(); toast('削除しました'); }
function save(){
const v=val(); const item = { id:Date.now(), date:new Date().toISOString(), version:'1.5', ...v };
try{
const logs = readLogs(); logs.unshift(item); writeLogs(pruneIfTooLarge(logs));
updateHistory(v); renderRecentTopics(); renderCandidates(); renderLogs();
toast('保存しました');
} catch(e){ toast('保存に失敗:容量超過'); }
}
function escapeHtml(s){ return (s||'').replace(/[&"']/g, m=>({ '&':'&','':'>','"':'"','\'':''' }[m])) }
/* タイマー(15分) */
let t=15*60; setInterval(()=>{ if(t{ [el.topic, el.w1, el.w2, el.w3, el.w4, el.w5, hypoEl, actEl, metricEl, periodEl, successEl].forEach(n=>n.value='');
ifthenList.innerHTML=''; addIfThen(); addIfThen(); el.out.textContent=''; toast('クリアしました'); };
el.save.onclick=()=>{ if(!guard()) return; gen(); save(); };
el.copy.onclick=async ()=>{ if(!guard()) return; gen(); await copyText(el.out.textContent); };
el.gen.onclick=()=>{ gen(); toast('更新しました'); };
/* 初期化 */
function init(){ loadUI(); renderLogs(); renderRecentTopics(); renderCandidates(); gen(); }
init();
})();
${new Date(it.date).toLocaleString()}






