RORK LABJP
ENGINE — Rork Max is powered by Claude Code and Claude Opus 4.6, generating native Swift apps directlyCORE ML — Rork Max reaches on-device Core ML inference alongside HealthKit, HomeKit, NFC, and App ClipsSEED — Rork raised a $15M seed led by Left Lane Capital in April 2026, joined by Peak XV and a16z SpeedrunM&A — Rork acquired the app builder Paperline and says it will stay acquisitive to bring in engineering talentMARKET — Gartner expects 75% of new applications to be built with low-code or no-code tools by the end of 2026GROWTH — The no-code AI platform market is projected to grow from $4.9B in 2024 to $24.8B by 2029ENGINE — Rork Max is powered by Claude Code and Claude Opus 4.6, generating native Swift apps directlyCORE ML — Rork Max reaches on-device Core ML inference alongside HealthKit, HomeKit, NFC, and App ClipsSEED — Rork raised a $15M seed led by Left Lane Capital in April 2026, joined by Peak XV and a16z SpeedrunM&A — Rork acquired the app builder Paperline and says it will stay acquisitive to bring in engineering talentMARKET — Gartner expects 75% of new applications to be built with low-code or no-code tools by the end of 2026GROWTH — The no-code AI platform market is projected to grow from $4.9B in 2024 to $24.8B by 2029
Articles/Dev Tools
Dev Tools/2026-05-13Intermediate

Three Things I Got Stuck on When Implementing Ambient Sound in a Healing App with Rork

Three common pitfalls when implementing ambient looping audio in meditation and healing apps built with Rork: loop clicks, iOS silent mode, and battery drain — with working expo-av code.

Rork498expo-av5ambient soundhealing appmeditation app3React Native201background music

I've been building apps independently since 2014, and my wellness, wallpaper, and manifestation apps have crossed 50 million cumulative downloads. In this category, sound is everything. The moment ambient audio stutters or cuts out, users snap back to reality — and a lot of them quietly uninstall.

Recently, I was prototyping a new meditation app in Rork and spent more time than I expected fighting ambient sound implementation. Rork handles screen layout and API wiring beautifully, but the code it generates for audio has a few recurring weak spots. Since I kept running into the same three problems, I want to write them down — with the fixes that actually worked.

Problem 1: A Click at the Loop Point

The first issue: a small "pop" or "click" sound every time the audio loops. When you ask Rork to implement looping ambient audio, it usually produces something like this:

// Pattern Rork commonly generates (prone to loop clicks)
const sound = await Audio.Sound.createAsync(
  require('./assets/rain.mp3'),
  { isLooping: true }
);
await sound.playAsync();

Setting isLooping: true should work in theory, but if there's any silence encoded at the tail of an MP3 file — which there almost always is — you'll hear a click on every loop. This isn't a Rork bug or a React Native bug; it's a fundamental quirk of the MP3 format.

Fix: Use WAV or m4a + manual loop control via PlaybackStatus

import { Audio } from 'expo-av';
import { useEffect, useRef } from 'react';
 
export function useAmbientSound(assetSource) {
  const soundRef = useRef(null);
 
  useEffect(() => {
    let isMounted = true;
 
    const loadAndPlay = async () => {
      await Audio.setAudioModeAsync({
        playsInSilentModeIOS: true,        // also covers Problem 2
        staysActiveInBackground: true,
        shouldDuckAndroid: false,
      });
 
      const { sound } = await Audio.Sound.createAsync(
        assetSource,
        { shouldPlay: true, volume: 0.6 }
      );
 
      if (!isMounted) return;
      soundRef.current = sound;
 
      // Loop fix: use onPlaybackStatusUpdate instead of isLooping
      sound.setOnPlaybackStatusUpdate(async (status) => {
        if (status.didJustFinish && isMounted) {
          await sound.replayAsync();
        }
      });
    };
 
    loadAndPlay();
    return () => {
      isMounted = false;
      soundRef.current?.unloadAsync();
    };
  }, []);
 
  return soundRef;
}

Listening for didJustFinish and calling replayAsync() is far more reliable on physical devices than relying on isLooping. For audio assets, use WAV or m4a (AAC) — avoid MP3 for anything that needs to loop seamlessly.

Problem 2: Silent Mode on iOS Kills All Audio

This one shows up in App Store reviews almost every time. A user opens your meditation app right before bed, their phone is on silent, and they hear nothing. It's one of those problems that's invisible in testing if you always test with sound on.

Rork's default generated code almost never includes the silent mode override. You have to add it explicitly:

// Call this at app startup or before loading any sound
await Audio.setAudioModeAsync({
  playsInSilentModeIOS: true,     // ← Without this, silent switch = no sound
  allowsRecordingIOS: false,
  staysActiveInBackground: true,
  interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
  interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX,
  shouldDuckAndroid: false,
  playThroughEarpieceAndroid: false,
});

This only needs to run once per session, but you'll also need corresponding entries in Info.plist for background audio mode. When prompting Rork, explicitly write "play audio even when iOS silent switch is on" — that phrasing significantly improves what it generates.

Problem 3: Battery Drain During Long Background Sessions

This one took me the longest to track down. During real-device testing, I noticed the app draining about 20% battery in an hour of background use — way more than expected for a simple ambient sound player.

Two causes turned out to be responsible. First, combining staysActiveInBackground: true with shouldDuckAndroid: false on a high-bitrate MP3 kept the audio decoder running at full priority the entire time. Second, the PlaybackStatus callback Rork generated was polling at the default 500ms interval — creating a constant drip of work on the JS thread even when nothing needed to change.

Fix: Optimize audio files + set progressUpdateIntervalMillis

const { sound } = await Audio.Sound.createAsync(
  assetSource,
  {
    shouldPlay: true,
    volume: 0.6,
    progressUpdateIntervalMillis: 1000,  // default 500ms → 1000ms
  }
);

For ambient audio, 96kbps AAC (m4a) is entirely sufficient. Streaming 320kbps MP3 or uncompressed WAV for hours of background playback is overkill. In my own apps, switching to 96kbps m4a reduced battery consumption by roughly 40%.

A Rork Prompt Pattern That Actually Works

Given these three problems, here's the prompt structure I now use when asking Rork to implement ambient audio:

Implement looping ambient sound with these requirements:
- Seamless looping — use didJustFinish + replayAsync(), NOT isLooping
- Play in iOS silent mode (playsInSilentModeIOS: true)
- Support background playback (staysActiveInBackground: true)
- Set progressUpdateIntervalMillis to 1000ms
- Asset format: m4a or WAV (not MP3)

Spelling out what to avoid, not just what to build, makes a significant difference in Rork's output quality.

The Part Rork Can't Do for You

Sound reaches users' emotions faster than visuals. After more than a decade building wellness apps, I'm more convinced of this than ever.

My grandfathers on both sides were shrine carpenters — craftsmen who believed that invisible joinery deserved the same care as what anyone could see. That feeling stuck with me. A single line of audio configuration that users will never notice is still worth getting right.

Rork lets you build the skeleton of an app at remarkable speed. But the texture of the experience — the parts that make someone keep coming back — still comes from the developer paying careful attention to exactly this kind of detail.

If you're building a meditation or wellness app with Rork, I hope the patterns here save you some time.

Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Dev Tools2026-05-05
Build a Podcast App with Rork: Complete Guide to Background Audio, RSS Parsing & Offline Playback
A complete production-level guide to building a podcast app with Rork. Covers expo-av background audio setup, RSS feed parsing, offline episode downloads, and App Store submission — all with working code examples.
Dev Tools2026-03-28
Build a Music Player App with Rork — Audio Playback Implementation Guide Using expo-av
Learn how to build a music player app with Rork and expo-av. This step-by-step guide covers playback controls, seek bars, playlist management, and background audio with practical code examples.
Dev Tools2026-07-10
Adding React Compiler to Expo Let Me Delete 41 Hand-Written memo Calls
I enabled React Compiler on Rork-generated React Native screens and measured the rerender counts with Profiler. Here is how I decided which memo and useCallback calls were safe to delete, how to find the components the compiler bailed out on, and how to catch regressions in CI.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →