React + Lottie で作る「焚き火アプリ」- もやもやを燃やして心を軽くするWebアプリ開発記
はじめに
頭の中のもやもやを紙に書いて焚き火に投げ込む。そんな体験をWebで再現した「焚き火アプリ」を個人開発しました。
技術スタック
{
"react": "^19.1.1",
"typescript": "~5.9.3",
"vite": "^7.1.7",
"framer-motion": "^12.23.24",
"lottie-react": "^2.4.1",
"tailwindcss": "^4.1.15"
}
実装のポイント
Lottieアニメーションの炎
炎のアニメーションはLottieを使用しています。火力に応じてサイズ、明るさ、速度が動的に変化します。
src/components/CampfireFlame.tsx
export const CampfireFlame: React.FC<CampfireFlameProps> = ({
flame,
lottieRef,
isMobile = false,
}) => {
const flameScale = calculateFlameScale(flame);
const flameOpacity = calculateFlameOpacity(flame);
const brightness = calculateBrightness(flame);
const saturation = calculateSaturation(flame);
return (
<motion.div
animate={{
scale: flameScale,
opacity: flameOpacity,
}}
transition={{
scale: { duration: 0.8 },
opacity: { duration: 0.8 },
}}
>
<Lottie
lottieRef={lottieRef}
animationData={campfireAnimation}
loop={true}
autoplay={true}
style={{
filter: `brightness(${brightness}) saturate(${saturation})`,
}}
/>
</motion.div>
);
};
ポイント:
- Framer Motionで滑らかなスケール変化
- CSSフィルターで炎の色味を動的に調整
- Lottie Refを使って速度を制御
炎の減衰システム
30秒間(ユーザーが10秒に変更)何も投げ込まないと、1ランクずつ火力が下がります。
src/hooks/useCampfireState.ts
const decayFlame = useCallback(() => {
setFlame((prev) => {
// 初期値より大きい場合のみ減衰
if (prev > FLAME_CONFIG.TARGET) {
const newFlame = prev - FLAME_CONFIG.RANK_STEP;
return Math.max(FLAME_CONFIG.TARGET, newFlame);
}
return prev;
});
setLastDecayTime(Date.now());
}, []);
src/constants.ts
export const FLAME_CONFIG = {
INITIAL: 20, // 初期値
TARGET: 20, // 減衰先
DECAY_INTERVAL: 10 * 1000, // 10秒
RANK_STEP: 15, // 1ランク分
};
紙切れのアニメーション
Framer Motionで紙がノートから焚き火へ飛んでいくアニメーションを実装。
src/components/PaperScrapAnimation.tsx
<motion.div
initial={{
x: scrap.origin.x - 100,
y: scrap.origin.y - 50,
scale: 1,
rotate: 0,
opacity: 1,
}}
animate={{
x: scrap.target.x - 100,
y: scrap.target.y - 50,
scale: 0.2,
rotate: 720,
opacity: 0,
}}
transition={{
duration: 4,
ease: [0.4, 0.0, 0.2, 1],
}}
>
<div className="paper-scrap">
{scrap.text}
</div>
</motion.div>
CSSでリアルな紙の質感:
.paper-scrap {
background: linear-gradient(to bottom, #fff9f0 0%, #fef6e8 50%, #fdf3dc 100%);
box-shadow: inset 0 0 20px rgba(210,180,140,0.2);
/* 上端にギザギザの破れた感じ */
clip-path: polygon(
0% 3%, 2% 0%, 4% 2%, 6% 0%, 8% 3%, /* ... */
);
}
デプロイ
Netlify
学んだこと
- Lottieアニメーションの制御方法
- iOS Safariの癖と対処法
感想
毒にも薬にもならないアプリって、なんでこんなに作るの楽しいんでしょうね。
作ったアプリに対して、このアプリ、何か意味あるの?と有用性や意義を聞かれることもありますが、ありません。それこそクソアプリの真髄だと思っております。