万華鏡アプリの BGM を「コード」じゃなく「モチーフ」で作り直した話

| デザイン | 万華鏡

タグ: #音楽 #UX #デザイン

万華鏡アプリで流していたヒーリング BGM が、聴いているうちに飽きる。コード進行で作るのをやめて、モチーフベースに作り直したら印象が変わった話です。

ヒーリング BGM の難しさ

万華鏡アプリは「画面をぼーっと眺めるアプリ」なので、BGM の良し悪しが体験に直結します。初期版では、3 つのコード(I → IV → V)を繰り返すヒーリング系の BGM を流していました。

が、自分で長時間流しっぱなしにしてみると、5 分くらいで飽きるのです。コード進行のループ感が、リラックスどころか軽くストレスになる。

モチーフベースという発想

音楽理論的にいうと、コードベースの BGM は「縦の構造」を組み立てる作り方です。これに対して、モチーフベースは「短い旋律フレーズ(モチーフ)」を複数用意し、それを変奏・転調しながら繋いでいく「横の構造」のアプローチです。

万華鏡のように「常に変化していく視覚」と相性が良いのはモチーフベースだろう、と判断して BGM を作り直しました。

実装はランダム遷移

4 つのモチーフ(各 8 小節程度)を用意し、再生中はそれらをランダムに遷移させます。同じモチーフが連続しないようにメモリを持たせ、転調も挿入して飽きにくくしました。

コードベースの BGM に比べて、聴いていて「次に何が来るか分からない」感が出るので、ぼーっと眺めている時間が延びました。

遷移ロジック自体はとてもシンプルで、「直前と同じモチーフは選ばない」「キーは小さい確率で転調する」の 2 ルールだけです。

class MotifScheduler {
  MotifScheduler(this.motifs, {Random? rng})
      : _rng = rng ?? Random();

  final List<Motif> motifs;
  final Random _rng;
  Motif? _previous;
  int _key = 0; // semitone offset

  Motif next() {
    final candidates = motifs.where((m) => m != _previous).toList();
    final picked = candidates[_rng.nextInt(candidates.length)];
    if (_rng.nextDouble() < 0.15) {
      const transposes = [-2, -1, 1, 2];
      _key = (_key + transposes[_rng.nextInt(transposes.length)]) % 12;
    }
    _previous = picked;
    return picked.transposed(_key);
  }
}

アプリ名を「万華鏡」へ

BGM リメイクと同時に、アプリ名を「万華鏡」というシンプルな日本語ひとことに変更しました。サブタイトルも「ヒーリング訴求」に変え、「物理シミュレーション」と「カメラ取り込み」を打ち出すようにしました。

アプリの方向性として「数学的な美しさ」「リラックス」「触っていて気持ちいい」というキーワードを軸に据え直したのです。

スパークル 5 段階の設定

ユーザーごとに「派手さ」の好みが違うので、スパークル(キラキラ感)を 5 段階で調整できるようにしました。

  • レベル 1: 控えめ(ヒーリング向け)
  • レベル 3: 標準
  • レベル 5: 派手(賑やかし向け)

設定が増えると UI が散らかるので、5 段階に絞った上で「変えたい人だけ深掘りできる」階層に置きました。

カラー+写真+ブレンドのデバッグ画面

開発中、テッセレーション(敷き詰め)のデバッグ用画面で「色」「写真」「ブレンド」モードを切り替えられる隠し機能を作り、これが意外と楽しかったので一部を製品 UI にも組み込みました。

開発ツールがそのまま製品の機能になるパターンは、個人開発ならではです。

まとめ

  • ループする BGM は意外と飽きる、モチーフ遷移にすると延命できる
  • アプリ名・サブタイトル・BGM はセットで方向性を再定義できる
  • 派手さは段階で可変にして、好みに合わせる

「ヒーリング」を本気で作るのは、思ったより難しい仕事でした。