Claude Codeで「逃げられない」集中タイマーアプリを1日で作ってApp Storeにリリースした
TL;DR
- YouTube視聴 × ポモドーロタイマーのアプリ「Tube道場」を個人開発
- Claude Codeを使ってMVP実装からApp Store申請まで実質1日
- 技術スタック: React Native (Expo) + TypeScript + Jotai + Firebase
📱 App Store: https://apps.apple.com/us/app/tubedojo/id6757209170
作ったもの
「Tube道場」は、YouTube動画を見ながらポモドーロタイマーで集中できるアプリです。
最大の特徴はFocus Mode(集中モード)。一度開始したら、タイマーが終わるまで中断できません。一時停止ボタンもリセットボタンも消えます。
| 機能 | 説明 |
|---|---|
| YouTube統合 | アプリ内でYouTube再生。BGM/環境音を聴きながら作業 |
| Focus Mode | 開始したら中断不可。意志力に頼らない強制集中 |
| リアルタイム接続数 | 「今○人が集中中」で孤独感を軽減 |
なぜ作ったか
自分自身、集中力が続かない問題を抱えていました。
- ポモドーロアプリを使っても「ちょっとだけ一時停止」が簡単すぎて逃げてしまう
- YouTubeでBGMを流すと、関連動画に吸い込まれる
- 一人で作業していると孤独でサボりがち
システム的に逃げ道を塞ぐアプリが欲しかったのです。
技術スタック
React Native (Expo SDK 52)
TypeScript
Jotai(状態管理)
Firebase Realtime Database(オンライン人数)
Cloudflare Workers(カウント集計)
Claude Codeでの開発フロー
1. CLAUDE.mdで文脈を共有
プロジェクトルートにCLAUDE.mdを作成し、以下を記載:
# Tube道場
## 概要
YouTube視聴 × ポモドーロタイマーの集中支援アプリ
## 技術スタック
- React Native (Expo)
- TypeScript
- Jotai(状態管理)
- Firebase Realtime Database
## ディレクトリ構造
src/
├── components/ # UIコンポーネント
├── stores/ # Jotai atoms
├── hooks/ # カスタムフック
└── screens/ # 画面コンポーネント
## 開発ルール
- 状態管理は必ずJotaiを使用
- コンポーネントは機能単位で分割
- Firebase操作はhooks/usePresence.tsに集約
このファイルがあることで、Claude Codeはプロジェクト全体を理解した上でコードを生成してくれます。
2. 設計書を先に書く
docs/app-design-doc.mdに画面設計を記載:
## メイン画面
┌─────────────────────────┐
│ 🔴 25:00 │ ← タイマー表示
│ │
│ ┌───────────────────┐ │
│ │ │ │ ← YouTube Player
│ │ (動画再生) │ │
│ │ │ │
│ └───────────────────┘ │
│ │
│ [▶ 開始] [⚙ 設定] │ ← Focus Mode中は非表示
│ │
│ 👥 42人が集中中 │ ← リアルタイム表示
└─────────────────────────┘
ASCII artでモックアップを書いておくと、Claude Codeが意図を正確に理解してくれます。
3. 機能単位で指示を出す
指示例:Focus Modeの実装
Focus Modeを実装してください。
要件:
- Focus Mode中は一時停止・リセットボタンを非表示
- 設定画面へのアクセスも無効化
- バックグラウンド移行を検知して警告モーダルを表示
- 状態はJotaiのatomで管理
Claude Codeはこの指示から、必要なコンポーネント・hooks・atomsを一貫して生成してくれました。
実装のポイント
Focus Modeの状態管理(Jotai)
// stores/focusMode.ts
import { atom } from 'jotai';
export const focusModeEnabledAtom = atom(false);
export const focusModeActiveAtom = atom(false);
// Focus Mode中かどうかを派生
export const isFocusRunningAtom = atom(
(get) => get(focusModeEnabledAtom) && get(focusModeActiveAtom)
);
// components/TimerControls.tsx
import { useAtomValue } from 'jotai';
import { isFocusRunningAtom } from '../stores/focusMode';
export const TimerControls = () => {
const isFocusRunning = useAtomValue(isFocusRunningAtom);
// Focus Mode中はボタンを表示しない
if (isFocusRunning) return null;
return (
<View>
<Button title="一時停止" onPress={handlePause} />
<Button title="リセット" onPress={handleReset} />
</View>
);
};
ボタンを「無効化」ではなく「非表示」にすることで、物理的に押せなくしています。
バックグラウンド検知
// hooks/useAppState.ts
import { useEffect } from 'react';
import { AppState } from 'react-native';
import { useAtomValue, useSetAtom } from 'jotai';
export const useBackgroundWarning = () => {
const isFocusRunning = useAtomValue(isFocusRunningAtom);
const setShowWarning = useSetAtom(showWarningModalAtom);
useEffect(() => {
const sub = AppState.addEventListener('change', (state) => {
if (isFocusRunning && state === 'background') {
// アプリがバックグラウンドに行ったら警告
setShowWarning(true);
}
});
return () => sub.remove();
}, [isFocusRunning]);
};
オンライン人数の取得(Firebase)
// hooks/usePresence.ts
import { useEffect, useState } from 'react';
import { ref, onValue, set, serverTimestamp } from 'firebase/database';
import { db } from '../config/firebase';
export const usePresence = () => {
const [onlineCount, setOnlineCount] = useState(0);
const visitorId = useRef(generateId()).current;
useEffect(() => {
// 自分のpresenceを登録
const presenceRef = ref(db, `presence/${visitorId}`);
set(presenceRef, {
visitorId,
expiresAt: Date.now() + 60000, // 1分後に期限切れ
});
// カウントを購読
const countRef = ref(db, 'stats/onlineCount');
const unsub = onValue(countRef, (snapshot) => {
setOnlineCount(snapshot.val() || 0);
});
return () => unsub();
}, []);
return { onlineCount };
};
App Store申請でハマったこと
「YouTube」がNGだった
サブタイトルに「集中タイマー × YouTube」と書いたら、Guideline 4.1で却下されました。
第三者のブランド名(YouTube)をメタデータに含めることはできません
修正内容:
- サブタイトル: 「集中タイマー × YouTube」→「集中タイマー × Tube動画」
- キーワード: 「YouTube」を削除
- 説明文: 「YouTube BGM」→「動画BGM」
Claude Codeを使ってみて
良かった点
- 一貫性: プロジェクト全体で同じパターンを適用してくれる
- 速度: 手作業で数時間かかる実装が数分で完成
- 細かい配慮: 画面回転時の状態復元など、指示していない部分も考慮
人間がやること
- 設計書を書く(何を作りたいかを明確に)
- 環境構築(Firebase設定、APIキー取得)
- デザインの最終判断
- App Store申請作業
まとめ
Claude Codeを使うことで、1日でMVPを完成させてApp Storeにリリースできました。
ポイントは:
- CLAUDE.mdで文脈を共有する
- 設計書を先に書く(ASCII artでモックアップ)
- 機能単位で明確に指示する
- 小さく始める(まずMVP、後から機能追加)
「こんなアプリあったらいいな」を形にするハードルが、劇的に下がっています。
リンク
- 📱 App Store: https://apps.apple.com/us/app/tubedojo/id6757209170
- 🤖 Claude Code: https://claude.ai/code
