RORK LABEN
FUNDING — RorkがLeft Lane Capital主導で$15Mのシードを調達。Peak XV・True Ventures・Goodwater・a16z Speedrunが参加しましたENGINE — Rork MaxはClaude CodeとClaude Opus 4.6で駆動。X で800万超のビューを集め、2週間で年間売上を倍増させましたSWIFT — Rork MaxはWebで初めてSwiftアプリを生成できるビルダーで、Apple伝統のXcodeを置き換える位置づけですPRODUCT — Rork MaxはiPhone・iPad・Apple Watch・Apple TV・Vision Pro・iMessageまでApple全域に対応しますCLASSIC — 通常のRorkはReact Native(Expo)で、英語の説明だけからiOS/Androidアプリを生成しストア配信できますPRICING — 無料で始められ、有料は月25ドル〜。Rork Maxは月200ドルですFUNDING — RorkがLeft Lane Capital主導で$15Mのシードを調達。Peak XV・True Ventures・Goodwater・a16z Speedrunが参加しましたENGINE — Rork MaxはClaude CodeとClaude Opus 4.6で駆動。X で800万超のビューを集め、2週間で年間売上を倍増させましたSWIFT — Rork MaxはWebで初めてSwiftアプリを生成できるビルダーで、Apple伝統のXcodeを置き換える位置づけですPRODUCT — Rork MaxはiPhone・iPad・Apple Watch・Apple TV・Vision Pro・iMessageまでApple全域に対応しますCLASSIC — 通常のRorkはReact Native(Expo)で、英語の説明だけからiOS/Androidアプリを生成しストア配信できますPRICING — 無料で始められ、有料は月25ドル〜。Rork Maxは月200ドルです
記事一覧/開発ツール
開発ツール/2026-06-24上級

呼吸の波に合わせて静かに震える、瞑想アプリの触覚をCoreHapticsで作る

expo-haptics の決まった振動では呼吸の「波」が作れません。CoreHaptics の連続イベントとパラメータカーブを Expo ネイティブモジュールから呼び出し、4-7-8 呼吸に同期した触覚を作る実装を、Swift と TypeScript のコードとともに整理します。

Rork443CoreHapticsExpo98ネイティブモジュール9個人開発161

プレミアム記事

瞑想と呼吸法のための小さなアプリを個人開発で出したとき、画面の円はゆっくり膨らんだり縮んだりするのに、指先には何も伝わってこないことがずっと気になっていました。目を閉じて使う場面が多いアプリなのに、視覚だけで呼吸を導いていたのです。

そこで expo-haptics を入れて、息を吸う合図と吐く合図に振動を足してみました。けれど、Haptics.impactAsync() で出せるのは一瞬の「トン」という打撃感だけです。私が欲しかったのは、4秒かけてゆっくり強くなり、止まり、また8秒かけて消えていく、息そのものに寄り添う波でした。単発の振動をいくら並べても、その連続した呼吸の感触にはなりません。

iPhone の Taptic Engine は、本当はもっと繊細な表現ができます。それを引き出す仕組みが CoreHaptics です。ここでは、CoreHaptics の連続イベントとパラメータカーブを使って呼吸に同期した触覚を作り、それを Expo ネイティブモジュールとして React Native(Rork で生成したアプリ)から呼べる形にするところまでを、実装コードとともに見ていきます。

なぜ expo-haptics だけでは呼吸の波にならないのか

expo-haptics が公開しているのは、大きく二系統です。impactAsync(style) の打撃感(light / medium / heavy など)と、notificationAsync(type) の成功・警告・失敗フィードバック。どちらも「あらかじめ決められた、ごく短いパターンを一回鳴らす」ためのものです。

呼吸の波に必要なのは、これとは性質が違います。整理すると、足りないのは次の3点です。

  1. 持続: 数秒間、途切れず鳴り続ける連続的な振動
  2. 強さの変化: その数秒の中で、強さがなめらかに上下すること
  3. 位相の制御: 吸う・止める・吐くという局面を、秒単位で指定できること

expo-haptics はこのいずれも提供していません。プリセットを setTimeout で並べても、間に無音の隙間ができ、「波」ではなく「点線」になってしまいます。指先に呼吸を感じてもらうには、振動そのものを連続イベントとして設計し、その強さを時間に沿って曲線で動かす必要があります。それができるのが CoreHaptics です。

やりたいことexpo-hapticsCoreHaptics
一瞬のタップ感得意可能(transient イベント)
数秒続く連続振動不可continuous イベント
強さを時間でなめらかに変える不可パラメータカーブ
導入の手軽さ数行で完了ネイティブモジュールが必要

つまり選択は二者択一ではありません。タップ感は expo-haptics に任せ、呼吸の波だけを CoreHaptics で足す、という併用が現実的です。私自身もこの形に落ち着きました。

CoreHaptics の連続イベントとパラメータカーブ

CoreHaptics で呼吸を表現する鍵は、CHHapticEventcontinuous(連続) タイプと、CHHapticParameterCurve(パラメータカーブ)の組み合わせです。

連続イベントは「ここから何秒間、振動を持続させる」という指定ができます。そしてパラメータカーブは「その持続の間に、強さ(intensity)を時刻ごとにどう変えるか」を制御点で描きます。吸う息なら 0 からゆっくり立ち上げ、吐く息なら最大からゆっくり 0 へ落とす。この曲線こそが、呼吸の波の正体です。

intensity(強さ)と sharpness(鋭さ)はいずれも 0.0〜1.0 の値を取ります。sharpness を低くすると角の取れた、丸く柔らかい振動になります。瞑想アプリでは sharpness を 0.3 前後に抑えると、刺すような感触が消えて呼吸になじみます。

吸う4秒・止める7秒・吐く8秒、いわゆる 4-7-8 呼吸の1サイクルを、Swift で組み立てると次のようになります。

import CoreHaptics
 
func makeBreathPattern(inhale: Double, hold: Double, exhale: Double) throws -> CHHapticPattern {
    let sharp = CHHapticEventParameter(parameterID: .hapticSharpness, value: 0.3)
 
    // 吸う: 強さ 0 → 0.8 へ立ち上げる連続イベント
    let inhaleEvent = CHHapticEvent(
        eventType: .hapticContinuous,
        parameters: [
            CHHapticEventParameter(parameterID: .hapticIntensity, value: 0.8),
            sharp
        ],
        relativeTime: 0,
        duration: inhale)
 
    let inhaleCurve = CHHapticParameterCurve(
        parameterID: .hapticIntensityControl,
        controlPoints: [
            .init(relativeTime: 0,      value: 0.0),
            .init(relativeTime: inhale, value: 1.0)
        ],
        relativeTime: 0)
 
    // 吐く: 強さ 0.8 → 0 へ落とす連続イベント(holdの分だけ後ろにずらす)
    let exhaleStart = inhale + hold
    let exhaleEvent = CHHapticEvent(
        eventType: .hapticContinuous,
        parameters: [
            CHHapticEventParameter(parameterID: .hapticIntensity, value: 0.8),
            sharp
        ],
        relativeTime: exhaleStart,
        duration: exhale)
 
    let exhaleCurve = CHHapticParameterCurve(
        parameterID: .hapticIntensityControl,
        controlPoints: [
            .init(relativeTime: exhaleStart,          value: 1.0),
            .init(relativeTime: exhaleStart + exhale, value: 0.0)
        ],
        relativeTime: 0)
 
    // hold(止める7秒)はイベントを置かない=無音。これが「息を止める」局面になる
    return try CHHapticPattern(
        events: [inhaleEvent, exhaleEvent],
        parameterCurves: [inhaleCurve, exhaleCurve])
}

ポイントは、止める局面に あえてイベントを置かないことです。無音そのものが「息を止めている」という体験になります。吸う・吐くの2つの連続イベントを、強さカーブで包む。これだけで、指先に呼吸の輪郭が現れます。

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

この記事の続きを読む

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

この記事で得られること
expo-haptics の単発フィードバックでは作れない、数秒かけて強さが上下する連続的な触覚を CoreHaptics のパラメータカーブで設計できます
CHHapticEngine を Expo Modules API(Swift)で包み、React 側から inhale/hold/exhale の秒数を渡して呼べるネイティブモジュールを実装できます
エンジンの自動停止・フォアグラウンド復帰・端末非対応・低電力モードという、本番で必ず踏む4つの落とし穴への対処まで持っていけます
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

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

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

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

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

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

関連記事

開発ツール2026-06-20
Rork が直せるバグと自分で直すバグを見分ける — エクスポートコードのトリアージ手順
Rork が自力で直すバグと、エクスポートしたReact Native/Expoコードを自分で手当てすべきバグを切り分けるトリアージ手順を、動くコードとともに整理しました。
開発ツール2026-06-18
Rork で出したアプリにオフライン優先を後付けする — 永続キャッシュと書き込みキューの設計
地下鉄でアプリを開いたら真っ白、というレビューが続きました。エラー画面を整えるだけでは足りず、Rork が出した Expo アプリに TanStack Query の永続キャッシュとオフライン書き込みキューを後付けした記録です。楽観的更新・再接続フラッシュ・再生成で消さない隔離まで実装込みで整理します。
開発ツール2026-06-14
Rork アプリのプッシュ許可、いきなり出して断られていませんか — 事前許諾で取りこぼしを減らす設計
Rork(Expo)で作ったアプリの起動直後に OS のプッシュ許可ダイアログを出すと、断られた瞬間にもう二度と出せなくなります。一度断られると再表示できない iOS の仕様を踏まえ、自前の事前許諾画面で許可率を底上げする設計を、実装コード込みで整理しました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →