← DEVLOG
Interactive2025.12.205 min read

Cosmic Breathing — A Nebula That Breathes With You

An interactive meditation where a nebula expands and contracts with your breath — 5 breathing patterns, breath-synced Web Audio ambient, Canvas nebula rendering

web-audiocanvasmeditationbreathingambient

The Starting Point — I Needed to Rest

When you're deep in code, time beyond the monitor dissolves. At 3 AM you look up and realize your shoulders are locked solid, and your breathing has gone shallow without you noticing.

While building space simulations and games, I found I needed the exact opposite — a space where nothing needs to be operated, where all you have to do is breathe. Just watch a nebula swell and shrink in time with your lungs.


Designing Breathing Patterns

Breathwork isn't a simple timer. Each technique has a different ratio of inhale, hold, exhale, and rest — and each ratio affects the body differently.

const PATTERNS: Record<PatternId, PatternDef> = {
  relax: { phases: [inhale(4), hold_in(4), exhale(6)] }, // Relaxation
  box: { phases: [inhale(4), hold_in(4), exhale(4), hold_out(4)] }, // Box
  sleep: { phases: [inhale(4), hold_in(7), exhale(8)] }, // 4-7-8 Sleep
  coherent: { phases: [inhale(5.5), exhale(5.5)] }, // Coherence
  sigh: { phases: [inhale(2.5), inhale(1.5), exhale(7)] }, // Cyclic Sigh
};

The 4-7-8 sleep pattern comes from Dr. Andrew Weil's breathing method. The long exhale activates the parasympathetic nervous system. Coherence breathing (5.5s–5.5s) is known to optimize heart rate variability (HRV). Cyclic sigh — a double inhale followed by a long exhale — was validated in Stanford research.


The Nebula Breathes

Breath progress (progress: 0~1) is mapped through easeInOut to the nebula radius. Inhale expands it; exhale contracts it.

function getBreathScale(state: BreathDrawState): number {
  const ep = easeInOut(progress);
  if (phase === 'inhale') return ep; // 0 → 1 expansion
  if (phase === 'hold_in') return 1; // maximum
  if (phase === 'exhale') return 1 - ep; // 1 → 0 contraction
  return 0; // minimum
}

Nebula color also responds to breath. As inhale deepens, a cool purple (80,60,180) linearly interpolates to warm pink (200,100,160). The deeper you breathe in, the warmer the nebula grows.

Nebula rendering uses an OffscreenCanvas batching technique — draw everything unblurred first, then apply a single blur filter pass. Since blur cost scales with pixel_count × radius², this is far more efficient than blurring individual elements.


Sound Follows Breath

The ambient pad layers 3–4 closely spaced sine waves to create natural beating. 110Hz and 111.5Hz — a 1.5Hz difference produces a slow undulation.

// Breath-synced drone: volume and frequency rise together on inhale
if (phase === 'inhale') {
  targetGain = 0.06 + progress * 0.06; // 0.06 → 0.12
  targetFreq = 55 + progress * 10; // A1(55Hz) → C#2(65Hz)
}

On inhale, the drone oscillator climbs from 55Hz to 65Hz, thickening the sound. On exhale, it descends back to 55Hz, opening up the space. This subtle 10Hz shift gives breath a physical dimension.

Each breathing pattern uses different pad frequencies. The sleep pattern is based on 82.41Hz (E2) for a deeper, lower tone; the box pattern uses 130.81Hz (C3) for a clearer timbre.


Streaks and Stats

Consistency matters in meditation. Each session's duration is accumulated, and consecutive days are tracked.

// On session completion
const today = new Date().toISOString().slice(0, 10);
const lastDate = storageGet<string>('breathing:lastDate', '');
const prevStreak = Number(storageGet<string>('breathing:streak', '0'));

const yesterday = new Date(Date.now() - 86400000).toISOString().slice(0, 10);
const newStreak = lastDate === yesterday ? prevStreak + 1 : lastDate === today ? prevStreak : 1;

How many consecutive days you've breathed, how many total minutes you've accumulated. It doesn't mean much in itself — but it's a small nudge to open it again tomorrow for just three minutes.


Closing Thoughts

I never expected to build a meditation app while making a space simulator.

But watching a nebula expand and contract while matching your breath, you realize the boundary between simulation and meditation is thinner than you'd think. Both are about creating rhythm — one follows the laws of physics, the other the rhythm of your body.

When your shoulders lock up in front of the monitor, try opening it for just three minutes.

Content related to this post

Try it yourself