Oisix Creator's Blog(オイシックスクリエイターズブログ)

オイシックス株式会社のエンジニア・デザイナーが執筆している公式ブログです。

AIを活用してモバイルアプリのアニメーション開発効率を高める技術

プラットフォーム部クライアントセクション マネジャーのohzonoです。
iOS・Android・Webとクライアント側のエンジニアリングマネジメントをしてます。


猫も杓子もプロンプトによって開発効率の向上を目指している2026年6月、UIのアウトプットについては、まだまだだなと感じる方も少なくないのではないでしょうか? 私は意外と悪くないなと思うんですが、UI以外のアウトプットと比べると、手直し頻度はUI周りが圧倒的に多いと感じます。


この記事では、AIを活用してモバイルアプリのアニメーション開発を行う機会を通して得られた学びを特にアニメーションに絞って共有していきます。




早速ですが、 アニメーション仕様書 をご存知でしょうか?

画面上で期待するアニメーションを可能な限り言語化し、デザイナー・エンジニア・PM/Bizなど関係者の認識を合わせるためのドキュメントです。ゲーム開発や、Web、動画作成の世界では聞き覚えのある方もいらっしゃるかもしれませんが、モバイルアプリ開発における私の経験では、口頭や同期的なミーティング、またはスクリーンレコーディング結果を非同期で動きを擦り合わせていくことが多く、明示的な仕様書として残す機会は今までありませんでした。

ところが生成AIの登場によって、プロンプトを書けば高速にプロトタイピングできるようになりました。
生成AI活用を前提とすると、最終的な成果物の品質はプロンプトとモデルの性能次第となる事もあり、アニメーションについて可能な限り言語化したドキュメント = アニメーション仕様書 の価値が高まっているのではないかと感じています。



この記事では、私がOisixアプリの新規入会オンボーディングで紙吹雪のアニメーションを実装した際に得られた3つの技術としてまとめました。 なお本記事はiOS開発を元にした経験ですが、iOS固有の話ではありません。また、FPSやヒッチの計測など、パフォーマンス計測の話は割愛します。

3つの技術とは?

  1. アニメーション仕様書を書いて、AIと人間の共通入力を作る技術
  2. たたき台を「ジャブ」として使い、曖昧な需要を引き出す/価値を創造する技術
  3. 時間と乱数を抽象化して、アニメーションをVRT化し継続的な品質保証を行う技術

それぞれご紹介しますが、まずは今回の題材をご紹介します。

題材: 紙吹雪アニメーション

OisixアプリのiOS版で、新規のご入会を検討していただいているお客様の体験を向上させるために入会前オンボーディング画面を新設しました。 そのうちの1画面に「お祝い感」を出したい意図があり、紙吹雪のアニメーションを実装しました。


入会前オンボーディング画面で舞う紙吹雪のアニメーション


※ 開発中の画面のキャプチャのため、訴求画像やテキストの一部は仮表示になっています。



ではそれぞれの技術について説明します。

技術1: アニメーション仕様書を書いて、AIと人間の共通入力を作る技術

1枚の仕様書を書いておくと、自分の頭の整理が進むだけでなく、AIに変更を依頼するときの精度も上がります 。 これは、AI活用しているエンジニアにとっては既に説明不要だと思いますが、アニメーション実装においても同様の効果があります。

紙吹雪を作る過程で、1枚の仕様書をリポジトリ内にMarkdownファイルとして残しました。

全文は後述しますが、たとえば、被写界深度を擬似表現するための 奥行き4レイヤー は、こんな表でまとめています。

レイヤー サイズ倍率 不透明度 ブラー 出現率
遠景(far) 0.38〜0.53x 50% なし 30%
中景(mid) 0.75〜0.98x 80% なし 30%
近景(near) 1.20〜1.50x 90% 1.5px 28%
最前面(veryNear) 1.80〜2.25x 70% 5.0px 12%


イメージ伝わるでしょうか。 この仕様書の中で、特に効果を実感したものは 調整可能なパラメータ一覧 です。


何を変えたいか パラメータ 現在値
紙吹雪の密度を増やす/減らす spawnRate 8個/秒
同時に表示する最大数 maxParticles 80個
落下速度を変える gravity 100
ヒラヒラ感を強く/弱く orientedDrag 0.14
横揺れの大きさ flutterAmplitude 60〜120
手前のボケ具合 DepthLayer.blurRadius 0 / 0 / 1.5 / 5.0
手前の大きさ DepthLayer.scaleRange 0.25〜1.50
色味 colorPairs ゴールド系4色



「ヒラヒラ感を強くしたい場合は orientedDrag を上げる(現在値: 0.14)」のように、 どこを触れば何が変わるか を表で並べておくと、デザイナーや他のエンジニアと数値で会話できるようになります。逆に「物理シミュレーションなので均一に流すことは構造的にできない」といった 動かせない軸 もここで明示できます。

以下はアニメーション仕様書の全文です。2026年3月時点のものをほぼそのまま転記しているため、現在のアプリの実装とは細部が異なる箇所があるかもしれませんが、雰囲気が伝わればさいわいです。



▶ 紙吹雪アニメーション仕様書(当時の全文・クリックで展開)

概要

オンボーディングTOP画面の背景に表示するゴールド系紙吹雪アニメーション。画面上端から紙吹雪が連続的にハラハラと舞い落ちる演出。

カラーパレット

ゴールド系の同系色4色で統一。各色に表面・裏面のペアがあり、紙が裏返る際に色が切り替わる。

名前 表面 裏面(やや暗め)
明るいゴールド rgb(255, 217, 77) rgb(217, 184, 51)
ゴールド rgb(255, 191, 26) rgb(217, 161, 13)
ダークゴールド rgb(217, 166, 13) rgb(184, 140, 0)
アンバー rgb(191, 140, 0) rgb(158, 115, 0)


背景色: #AD2511(ブラウンレッド)との補色関係でコントラストが高い。

紙吹雪の形状

4種類の形状をランダムに使用(均等配分)。


形状 ベースサイズ 説明
リボン 6×16 pt 細長い短冊状
正方形 8×8 pt 最も紙吹雪らしい形状
5×5 pt パンチ穴の紙片
菱形 7×10 pt ヒラヒラ感を強調する形状


※ 実際の表示サイズは奥行きレイヤーに応じて 0.4倍〜2.25倍 になる(後述)。

奥行き(4レイヤー構成)

被写界深度を擬似表現するため、4段階の奥行きレイヤーを設定。 大きいものほどボケて手前に見え、小さいものはクリアで奥に見える。


レイヤー サイズ倍率 不透明度 ブラー 出現率 視覚的な印象
遠景(far) 0.38〜0.53x 50% なし 30% 小さくクリア、奥で舞っている
中景(mid) 0.75〜0.98x 80% なし 30% 標準サイズ、メインの紙吹雪
近景(near) 1.20〜1.50x 90% 1.5px 28% やや大きく、わずかにボケ
最前面(veryNear) 1.80〜2.25x 70% 5.0px 12% 大きくボケて手前を横切る


※ サイズ倍率 = 奥行きスケール(0.25〜1.50) × 1.5倍(全体拡大)。
※ 最前面は不透明度70%にすることで主張しすぎないようにしている。

動きの仕様

放出パターン:


  • 連続放出: 画面上端(画面外 y=-20pt)からランダムなX位置に出現
  • 生成レート: 約8個/秒
  • 同時存在上限: 80個
  • 初速: 下方向にゆっくり(10〜40 pt/s)


紙吹雪の動きは、3種の要素の組み合わせで表現している。


  1. ヒラヒラ(tumble / 前後回転): 紙が前後に回転し、面が水平になると空気抵抗が増して減速 → 面が垂直になると加速。この 速度の緩急 がヒラヒラ感の源。回転速度 2.5〜6.0 rad/s。
  2. くるくる(flip / 横回転 + 裏返り): 紙が横方向に回転し、表面と裏面が交互に見える。裏返り時に 色が切り替わる ことで視覚的に認識しやすい。回転速度 3.0〜7.0 rad/s。
  3. 横揺れ(flutter): sin波で左右に揺れながら落ちる動き。各紙吹雪ごとに 周期・振幅・位相がランダム で、均一感が出ない。振幅 60〜120、周期 2.5〜5.5 Hz。


物理パラメータ:


パラメータ 説明
重力 100 pt/s² やや弱め(紙は軽い)
基本空気抵抗 0.03 常に働く最低限の抵抗
向き依存空気抵抗 0.14 面が水平時に追加される抵抗(ヒラヒラの源)
回転減衰 0.985/フレーム 回転が徐々に減速するが長く持続


寿命とフェードアウト:


  • 寿命: 7〜10秒(ゆっくり落ちるため長め)
  • フェードアウト: 寿命の70%経過後から徐々に透明に


画面内の表示範囲(グラデーションマスクにより、画面上下端で自然にフェードイン/アウト):


位置 効果
上端 0〜8% フェードイン(出現)
中央 8〜60% 完全表示
下部 60〜78% フェードアウト(消失)
下部 78%〜 非表示(CTAボタン領域を保護)

アクセシビリティ

  • iOS「視覚効果を減らす」がONの場合、アニメーションは非表示(EmptyView)

調整可能なパラメータ

デザイナーフィードバックに応じて調整しやすい主要パラメータ:


何を変えたいか パラメータ 現在値
紙吹雪の密度を増やす/減らす spawnRate 8個/秒
同時に表示する最大数 maxParticles 80個
落下速度を変える gravity 100
ヒラヒラ感を強く/弱く orientedDrag 0.14
横揺れの大きさ flutterAmplitude 60〜120
手前のボケ具合 DepthLayer.blurRadius 0 / 0 / 1.5 / 5.0
手前の大きさ DepthLayer.scaleRange 0.25〜1.50
色味 colorPairs ゴールド系4色

以上がアニメーション仕様書全文です。


技術2: たたき台を「ジャブ」として使い、曖昧な需要を引き出す/価値を創造する技術

2つ目は、開発の進め方そのものに関する技術です。

このアニメーションは、最初から「紙吹雪をください」と依頼を受けて作ったわけではありません。むしろ最初は静止画でした。

そこで私が取った方法は、 AIにたたき台を量産させて、それをBizやデザイナーに見せて反応をうかがう ことです。

プロトタイプを量産させるなどアイデアの発散フェーズにおいては、AIは活用しやすいです。 最初の試作では、桜の花吹雪・グラデーション球体・メッシュグラデーション・オーロラ・玉ボケライトの5種類を、DEBUGメニューから切り替えられる形で展開しました。最終的にこの5種類はどれも採用に至りませんでしたが、議論の起点となり、「こんなアニメーションができるなら...」と期待値を高めてくれました。


5種類の背景アニメーション試作(桜→グラデ球体→メッシュ→オーロラ→玉ボケ)


もともとデザイナーさんは静止画ベースで画面を考えてくださっていたのですが、「こんなアニメーションもできますよ」とこの5パターンを見せたこともあり、「できたら動かしてほしい」という要求が出てきて実装に至りました。たたき台を見せていなければ、おそらく静止画のままで合意していたと思います。

ジャブを打って、需要を引き出すループ

そこからもう一段、紙吹雪に絞ったたたき台を2種類作りました。

素朴版 物理シミュレーション版

このプロセスを通じて、以下のような 言語化されていなかった要件をフィードバックしていただけました

* 紙吹雪の色を同系色にまとめれないか
* 若干紙吹雪のサイズを大きくできないか
* 画面上からハラハラ落ちてくる動きにできないか

このフィードバックを受けて、私も「奥行きを出すこと」を思いつき、Promptした結果、本記事冒頭に添付した成果物に至りました。


正直なところ、最終的に採用された紙吹雪の仕様は、当初の私自身の頭の中にも存在しなかったものでした。たたき台をジャブとして打って、反応を引き出し、また次のたたき台を出す。このループの中で、関係者全員が納得する形に収束していったように思います。


現時点ではAIによって、 ジャブを実装負荷小さく、速く打てるようになったこと にメリットがあると感じています。ただし、発散のコストが下がった分、収束のコストが上がる可能性は考慮する必要があります。どちらも楽しいですが(納期さえ無ければ...)。

技術3: 時間と乱数を抽象化して、アニメーションをVRT化し継続的な品質保証を行う技術

3つ目は、記事を書くにあたって実際にやってみた取り組みです。

VRT = Visual Regression Testing は、UI上の変更前のスクリーンショット(正解画像)と変更後のスクリーンショットをドット単位で比較し、差分(ズレや色の違い)の有無によって描画をテストする手法です。これ自体は、クライアントアプリケーション開発においては比較的浸透してきている技術だと思います。

アニメーションのテストについて、正直私は詳しくなく学習中です。

ただ、今回の紙吹雪は、実装している物理シミュレーションが 同じ条件を渡せば、毎回ぴったり同じ動きを返してくれる ことに気づきました。それぞれの紙は「初期位置・初速・回転・寿命・乱数シード」が決まれば、以後の挙動は時刻 t の関数として一意に定まります。


つまり、乱数を外から差し替えてしまえば、 アニメーションを止めずに、任意の時刻でスクリーンショットを撮れる はずです。実際にやってみました。

抽象化のレシピ

本番コードに手を入れたのは2点だけです。

  • Double.random(in:) など各所の乱数呼び出しクラス、 RandomNumberGenerator をDIで差し替えられる形にする(本番ではシステム乱数、テストではシード固定)
  • start() メソッドの引数に開始時刻を追加

画面サイズはもともと update(date:size:) の引数として渡していたので変更不要でした。

こうすると、紙吹雪のシステムは (seed, size, t) から画面を返す純粋関数として扱えるようになります。

Swift Testingのparameterized testで時刻を振る

テストコードは Swift Testing の @Test(arguments:) で時刻 t をパラメータ化しました。

import Testing
import SnapshotTesting
import SwiftUI
@testable import FeatureXXX

@MainActor
struct ConfettiVRTSnapshotTests {

    private static let canvasSize = CGSize(width: 390, height: 844)

    @Test("固定シード+仮想時刻の紙吹雪スクリーンショット",
          arguments: [0.5, 1.0, 2.0, 3.0])
    func confettiSnapshot(at seconds: Double) {
        let size = Self.canvasSize
        let system = GoldConfettiSystem(seed: 42)
        let origin = Date(timeIntervalSince1970: 0)
        system.start(now: origin)

        let fps = 60.0
        let steps = Int((seconds * fps).rounded())
        for step in 1...steps {
            system.update(
                date: origin.addingTimeInterval(Double(step) / fps),
                size: size
            )
        }

        assertSnapshot(
            of: ConfettiSnapshotView(system: system, size: size),
            as: .image(layout: .fixed(width: size.width, height: size.height)),
            named: "t\(seconds)s"
        )
    }
}

seed: 42 で乱数を固定し、既存実装の兼ね合いから1/60秒刻みで仮想時刻を進めています。乱数シードと時刻を固定しているため、 何度実行してもぴったり同じ位置・向き・色の紙吹雪が再現されます

結果: 時系列で並べてみる

以下は t = 1.0s / 2.0s / 3.0s のスクリーンショットです。


t = 1.0s t = 2.0s t = 3.0s


これができると、AIが行ったパラメータ変更や、リファクタで定数がうっかりズレた、というような変化を 画面差分として自動で検知できる ようになります。デザイナーから「ヒラヒラ感をもう少し強く」と要望が来たときも、変更前後の差分画像を並べて合意形成する材料になりそうです。

脱線: カンファレンスのインプットに助けられました

少し本筋から逸れますが、昨年参加したカンファレンスのインプットに助けられたので紹介させてください。

紙吹雪は最大80枚のパーティクルを毎フレーム動かすため、素朴に実装するとSwiftUIの再描画が重くなり、カクつきが出ました。これをどう軽くするか悩んでいたとき、try! Swift Tokyo 2025 で聴いた Pradnya Nikam さんのセッション「Understanding Render Loop to optimise SwiftUI」を思い出しました。

SwiftUIの描画が「状態の変化 → Viewの差分計算 → 描画」という段階(Render Loop)で動くこと、そしてどこに無駄が生まれやすいかを知っていたおかげで、「パーティクルを @State の配列で持つと毎フレーム重い差分計算が走る」と見当がつきました。最終的には、パーティクルを参照型のクラスで保持し、1フレームあたりのbody評価が1回で済むようにする、といった手を打っています。


冒頭で「パフォーマンス計測の話は割愛します」と書いたので深入りはしませんが、カンファレンスで学んだ知識が、1年後の実務の実装判断に効いてくる体験は、素直にうれしいものでした。



youtu.be

さいごに

ここまで3つの技術を整理して書いてきましたが、これらを最初から計画して進めていたわけではありませんでした。 実際の流れは、試行錯誤を含んだもので、

  1. AIで作ったたたき台をBizに見せたところ、思いがけず需要が引き出せたことで「やろう」となった
  2. 実装に入ってみると、「リッチに見える紙吹雪」を物理的に分解する作業に思いのほか苦戦した
  3. 試行錯誤する過程でパラメータが散らばってきたため、整理目的で書き始めた仕様書が、想像以上に効くと気づいた
  4. 仕様書のおかげでパラメータが整理され、同じ条件で毎回同じ動きをすると客観的に理解したことで、「これってVRTに乗せられるのでは?」というアイデアに到達した

という流れでした。


つまり今回の3つの技術は、すべて 後から振り返って得られた学びを整理したもの です。


アニメーション仕様書という単語が、皆様の頭の中に少しでも残ったら嬉しいです。Lottieなどのアニメーション技術で足りる場面はそれらで十分ですし、無理にエンジニアがこの仕様書を書く必要もないと思います。ただ、AIに変更を任せたいときには、 動かせる軸と動かせない軸を1枚にまとめた仕様書 が、思った以上に効いてくれます。


今回ご紹介した紙吹雪のアニメーションは、入会前のオンボーディング画面で動いているものなので、入会不要でどなたでも実機でご確認いただけます。iOSをご利用の方は、よろしければ以下からインストールして、実際の動きを見てみてください。


https://apps.apple.com/us/app/oisix/id929573675?ppid=e932df94-019b-4187-8c4e-3e8bb2aa17b4


以上です!

Oisix Creator's Blogはオイシックス株式会社のエンジニア・デザイナーが執筆している公式ブログです。

オイシックス株式会社では一緒に働く仲間を募集しています