万華鏡アプリの BGM を「コード」じゃなく「モチーフ」で作り直した話
| デザイン | 万華鏡
タグ: #音楽 #UX #デザイン
万華鏡アプリのヒーリング BGM を自分で流しっぱなしにしたら、5 分で飽きました。3 つのコードを回すのをやめて、4 つのモチーフをランダムに遷移させる作りに変えたら、眺めていられる時間が延びた話です。
ヒーリング 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 はセットで方向性を再定義できる
- 派手さは段階で可変にして、好みに合わせる
「ヒーリング」を本気で作るのは、思ったより難しい仕事でした。次に触るときは、音のほうをもう少し勉強してからにします。