RORK LABEN
DEADLINE — 本日8月31日から、Google Play への新規アプリ提出と既存アプリの更新は Android 16(API レベル36)以上をターゲットにする必要がありますSCOPE — 既存アプリは削除されません。ただし要件を下回ったままだと、新しい Android バージョンのユーザーには表示されなくなります。消えないが届かなくなる、という形の影響ですEXTENSION — 間に合わない場合、11月1日までの延長を申請できます。申請という選択肢があること自体を知らずに当日を迎える例が毎年出ていますMIGRATION — Rork の生成物は React Native と Expo が土台です。targetSdkVersion を上げる作業は、Expo SDK とネイティブ依存の更新を必ず伴いますTESTING — 本当に時間を取られるのはビルドが通った後です。バックグラウンド実行制限、権限モデル、フォアグラウンドサービスの型指定が一斉に効きますORDER — 現実的な順序は、延長申請の可否を確認し、Expo SDK のアップグレード計画を立て、最後に最小構成で実機の回帰テストを行うことです。当日に全部やると原因が追えませんDEADLINE — 本日8月31日から、Google Play への新規アプリ提出と既存アプリの更新は Android 16(API レベル36)以上をターゲットにする必要がありますSCOPE — 既存アプリは削除されません。ただし要件を下回ったままだと、新しい Android バージョンのユーザーには表示されなくなります。消えないが届かなくなる、という形の影響ですEXTENSION — 間に合わない場合、11月1日までの延長を申請できます。申請という選択肢があること自体を知らずに当日を迎える例が毎年出ていますMIGRATION — Rork の生成物は React Native と Expo が土台です。targetSdkVersion を上げる作業は、Expo SDK とネイティブ依存の更新を必ず伴いますTESTING — 本当に時間を取られるのはビルドが通った後です。バックグラウンド実行制限、権限モデル、フォアグラウンドサービスの型指定が一斉に効きますORDER — 現実的な順序は、延長申請の可否を確認し、Expo SDK のアップグレード計画を立て、最後に最小構成で実機の回帰テストを行うことです。当日に全部やると原因が追えません
記事一覧/開発ツール
開発ツール/2026-07-15上級

Rorkの癒しアプリにスリープタイマーを付けたら、フェードアウトが実際の音とズレた話

Rorkが生成するスリープタイマーは、壁時計のsetIntervalで音量を下げます。数値上は30分でも、実際の音はもっと早く消えたり不自然に途切れたりします。フェードを再生位置で駆動し直す実装と、対数カーブ・停止処理・画面ロック時の限界までを実運用の視点でまとめました。

Rork547expo-av5スリープタイマーReact Native233音声処理癒しアプリ2

プレミアム記事

個人開発で Relaxing Healing という癒し系アプリを長く運営していると、「音が消える瞬間」の設計がアプリの印象を大きく左右することを何度も実感してきました。眠りに落ちる直前、音がプツッと切れれば人は目を覚まします。だからこそスリープタイマーのフェードアウトは、地味ですが最後の一手として重要な機能です。

先日、新しい癒しアプリの試作をRorkで進めていたとき、このスリープタイマーで数時間つまずきました。シミュレータでは30分後にきれいに音が消えていくのに、実機で試すと「思ったより早く音が小さくなる」「最後の数秒だけ急に途切れる」という違和感が残ります。原因を追ってみると、Rorkが生成したコードには音声フェード特有の落とし穴がいくつも重なっていました。同じジャンルのアプリを作る方が必ずぶつかる部分なので、直し方を整理しておきます。

Rorkが生成するスリープタイマーの典型形

「30分後に音量をゆっくり下げて停止するスリープタイマーを付けて」とRorkに依頼すると、多くの場合こういうコードが返ってきます。

// Rorkが生成しやすいパターン
const FADE_MS = 30_000; // 最後の30秒でフェード
const TICK_MS = 200;
 
function startSleepTimer(sound, totalMinutes) {
  const stopAt = Date.now() + totalMinutes * 60_000;
 
  const id = setInterval(async () => {
    const remaining = stopAt - Date.now();
    if (remaining <= 0) {
      await sound.stopAsync();
      clearInterval(id);
      return;
    }
    if (remaining <= FADE_MS) {
      const volume = remaining / FADE_MS; // 1.0 → 0.0
      await sound.setVolumeAsync(volume);
    }
  }, TICK_MS);
 
  return id;
}

一見すると正しく見えます。Date.now() で残り時間を測り、フェード区間に入ったら線形に音量を下げる。動かすと確かに音は小さくなっていきます。けれど、このコードは3つの層で実際の音とズレます。

壁時計で測ると、なぜ実際の音とズレるのか

第一の問題は、setInterval が壁時計(wall clock)を基準にしていることです。setInterval(fn, 200) はぴったり200msごとには呼ばれません。JSスレッドが画像のデコードやリスト描画で忙しければ、200msの間隔は250msにも400msにも伸びます。フェードのように「なめらかさ」が命の処理では、この揺らぎがそのまま音量のガタつきになります。

第二に、sound.setVolumeAsync() は非同期です。200msごとに await を挟むと、ネイティブ側への反映が詰まったときにコールバックが積み上がり、音量の更新が飛び飛びになります。

そして第三に、最も見落とされやすいのが「音声の再生位置」と「壁時計」が同じ速度で進むとは限らないことです。オーディオセッションが割り込み(電話・他アプリの音)から復帰したとき、あるいはループの継ぎ目で僅かに再バッファが起きたとき、実際に鳴っている音の位置は壁時計から遅れます。壁時計だけを見ていると、音はまだ鳴っているのにタイマーが先に「終わり」と判断し、フェードの途中で急に切れてしまうのです。

観点壁時計 setInterval再生位置ドリブン
基準にする時間Date.now()実際の再生位置 positionMillis
JSが重いとき間隔が伸びて音量がガタつく次の更新で正しい音量に追従
割り込み復帰後音と時間がズレて途中で切れる音の位置に同期し続ける
フェードの決定性累積誤差で毎回ぶれる位置から一意に決まる

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
Rorkが吐くsetIntervalフェードがなぜ実際の音とズレるかを理解し、再生位置で駆動する正しい実装に置き換えられる
線形に音量を下げると不自然に速く消えて聞こえる理由と、対数カーブで自然なフェードにする具体的な計算を手に入れられる
画面ロック中はJSのフェードが止まるという限界を正しく知り、事前フェード済みのテール音源で確実に消す現実解を選べる
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥2,480 の永久アクセス
メンバーシップを見る →

関連記事

開発ツール2026-05-13
Rork で癒し系アプリのアンビエントサウンドを実装して詰まった3つのこと
癒し・瞑想系アプリのアンビエントサウンド実装でRorkが苦手な3つの問題を解決します。ループの継ぎ目で音が途切れる、iOSのサイレントモードで無音になる、バックグラウンド再生でバッテリーが消耗する症状を、expo-avの実践コードとプロンプト例で対処します。
開発ツール2026-05-05
Rork のポッドキャストアプリを本番運用へ — expo-audio への移行・割り込みからの復帰・ダウンロード再開
Rork のポッドキャストアプリを実運用に耐えさせるための実装メモ。SDK 55 で消える expo-av からの移行、着信割り込みからの復帰、中断されたダウンロードの再開、iCloud バックアップと容量予算の設計まで、動くコードで扱います。
開発ツール2026-03-28
Rork で音楽プレイヤーアプリを作る — expo-av によるオーディオ再生の実装ガイド
Rorkとexpo-avで音楽プレイヤーアプリを構築します。オーディオの読み込みから再生・一時停止、シークバーと再生コントロールUI、プレイリスト管理と曲の切り替え、バックグラウンド再生と通知コントロールまで、実践的なコード例とともに進めます。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →