一枚絵リアルタイム2Dアニメーションアプリ仕様書
作成日: 2026-05-13
対象: 一枚のイラストから、Live2D風にリアルタイム操作できる2Dキャラクターアプリを実装するための仕様
ライセンス方針: アプリ本体はMIT License。依存関係はMIT互換ライセンスのみ許可し、GPL/AGPL/LGPL、商用プロプライエタリSDK、用途制限付きモデルは禁止。
改定履歴
| 日付 | 内容 |
|---|---|
| 2026-05-13 | 初版作成 |
| 2026-05-13 | レビュー指摘を反映。ONNX Runtime Web、MediaPipeモデル、三角形分割、CSP互換、ショートカット、設定保存、性能測定の条件を明確化 |
1. 目的
本アプリは、ユーザーが読み込んだ一枚のキャラクターイラストを、手動または半自動でパーツ化、メッシュ化、リギングし、マウス、キーボード、ゲームパッド、音声、Webカメラの顔トラッキング入力でリアルタイムに動かせる状態にする。
Live2D Cubism SDKやLive2D形式を利用、模倣、変換するものではない。独自の2Dメッシュ変形、パラメータ、物理揺れ、プロジェクト形式を持つMITライセンスのアプリとして実装する。
2. 成功条件
- PNGまたはWebPの一枚絵を読み込み、アプリ内で安全に管理できる。
- 最低限の手動編集で、顔、髪、目、口、首、胴体、腕などの2Dパーツ領域を定義できる。
- 各パーツに三角形メッシュを作成し、制御点、ボーン、変形パラメータを割り当てられる。
顔角度X/Y/Z、まばたき、口開閉、笑顔、呼吸、髪揺れなどのパラメータをリアルタイムに反映できる。- Webカメラ入力はローカル処理のみで、ユーザーの明示許可なしに画像、映像、モデル、プロジェクトを外部送信しない。
- プロジェクトファイル、書き出しファイル、ログに個人情報や絶対パスを不用意に含めない。
- セキュリティレビュー、ライセンスレビュー、依存脆弱性チェック、基本テストを通過しない限りリリース不可とする。
3. 非目標
- Live2D Cubism SDK、Cubismモデル、Cubism形式との互換性。
- 一枚絵から完全自動で商用品質のリグを生成すること。
- クラウドAI処理を必須にすること。
- ユーザー画像を学習データとして収集すること。
- NFT、透かし除去、著作権保護回避、他者キャラクターの無断利用を助長する機能。
4. 想定ユーザー
- 配信者、動画制作者、個人クリエイター。
- 既存の一枚絵を簡易的に動かしたいイラストレーター。
- MITライセンスの範囲で改造、組み込み、研究利用したい開発者。
UI文字列はすべて日本語とする。ボタン、ラベル、設定、エラー、ヘルプ、チュートリアルで既存日本語文字列を英語化してはならない。
5. 配布形態
5.1 対象プラットフォーム
初期版はデスクトップアプリを対象にする。
- Windows 10以降。
- macOS 13以降。
- Linuxはベータ扱い。
5.2 技術スタック
推奨構成:
| 領域 | 採用候補 | ライセンス | 採用理由 |
|---|---|---|---|
| デスクトップ基盤 | Tauri v2 | MIT/Apache-2.0 | WebViewとRustバックエンドで権限を細かく制限できる |
| フロントエンド | React + TypeScript + Vite | MIT中心 | UI実装、状態管理、ビルドが容易 |
| 2Dレンダリング | PixiJS | MIT | WebGL/WebGPU系2D描画に強い |
| 3D補助表示 | three.js | MIT | 必要時の補助ビュー、将来の3D入力確認に使える |
| 三角形分割 | earcut | ISC | 初期版の自動メッシュ生成に使う。CDN利用は禁止しnpm同梱のみ許可 |
| 推論ランタイム | ONNX Runtime Web | MIT。ただしnpm配布物、WASM、ThirdPartyNotices確認必須 | ローカル推論候補。禁止ライセンスや本方針に反する同梱物があれば不採用 |
| ネイティブ処理 | Rust | MIT/Apache-2.0 | ファイル検証、保存、権限境界、重い処理に使う |
顔トラッキング候補:
| 候補 | ライセンス | 判定 |
|---|---|---|
| MediaPipe Tasks Vision | Apache-2.0。ただし.taskモデルは個別確認 | 採用保留。npmパッケージ、WASM、モデルファイル、再配布条件、オフライン同梱手順を確認できた場合のみ採用可 |
| 独自ONNXモデル | モデルごとに確認 | モデルライセンス、学習データ権利、再配布可否を個別審査 |
| Live2D Cubism SDK | 独自ライセンス | 採用禁止 |
依存関係は「MIT、Apache-2.0、BSD-2-Clause、BSD-3-Clause、ISC、Zlib、MPL-2.0」を許可候補とする。MPL-2.0はファイル単位の開示義務があるため、コア依存には原則使わず、採用時はレビュー必須。
推論、顔トラッキング、モデル配布の採用ゲート:
- ONNX Runtime Webは、実際に採用するnpmバージョンのパッケージ内容と
ThirdPartyNotices.txtを確認し、禁止ライセンス、用途制限、再配布制限、逆コンパイル禁止など本プロジェクトの方針に反する条項がない場合のみ採用する。 - ONNX Runtime WebのWASMバックエンド、WebGPUバックエンド、バンドル済み
.wasmファイルは、ソース本体のMIT表記だけで判断しない。 - ONNX Runtime Webが採用不可の場合は、推論依存なしのMVPに切り替え、顔トラッキングをv0.2以降へ延期する。
- MediaPipeは、
@mediapipe/tasks-vision本体と、使用する.taskモデルファイルを別々に審査する。 - MediaPipeモデルはCDNから取得しない。Google公式手順に従い、モデルをプロジェクト内へ保存し、SHA-256、配布元URL、ライセンス、再配布可否を
licenses/model_inventory.mdに記録する。 - MediaPipeモデルをオフライン同梱できない場合は採用せず、再配布可能な独自ONNXモデル、またはカメラ非対応MVPへ切り替える。
- npm、WASM、モデルファイルはすべてロックファイルとハッシュで固定し、リリースごとに再審査する。
6. アプリ構成
6.1 主要画面
| 画面 | 目的 | 主なUI |
|---|---|---|
| ホーム | 最近使ったプロジェクト、新規作成、読み込み | 新規作成、プロジェクトを開く、最近使った項目 |
| 素材読み込み | 画像の読み込み、検証、キャンバス設定 | 画像を選択、背景を透過として扱う、作成 |
| パーツ編集 | 領域分割、マスク、前後関係 | 選択、ブラシ、消しゴム、自動候補、パーツ一覧 |
| メッシュ編集 | 頂点、三角形、制御点編集 | 頂点追加、自動メッシュ、左右対称、重み表示 |
| リグ編集 | パラメータ、キーフォーム、ボーン、デフォーマ | パラメータ、キー追加、補間、物理設定 |
| プレビュー | 入力連動、録画、負荷確認 | 再生、停止、カメラ連動、音声連動 |
| 書き出し | プロジェクト、ランタイムパッケージ、動画 | 保存、別名で保存、ランタイムを書き出し |
| 設定 | 権限、カメラ、保存先、セキュリティ | カメラを使用、外部通信を許可しない、依存ライセンスを表示 |
6.2 ユーザーフロー
新規作成を押す。- PNGまたはWebPを選択する。
- アプリがファイルサイズ、拡張子、シグネチャ、画像寸法、デコード可否を検証する。
- パーツ編集画面で、手動または自動候補から領域を作る。
- 各パーツに前後関係を設定する。
- 自動メッシュを生成し、必要に応じて頂点を修正する。
顔角度X/Yなどのパラメータに対して変形キーを登録する。- カメラ、マウス、音声などの入力をパラメータへマッピングする。
- プレビューで破綻、遅延、CPU/GPU負荷を確認する。
.motion2dprojとして保存する。
7. 機能要件
7.1 画像読み込み
対応形式:
- PNG。
- WebP。
- JPEGは初期版では任意。透過が使えないため非推奨として扱う。
制限:
- 最大ファイルサイズ: 50 MB。
- 最大画像寸法: 8192 x 8192 px。
- 最大総ピクセル数: 67,108,864 px。
- アニメーションPNG、アニメーションWebPは初期版では先頭フレームのみ許可、または拒否する。
- EXIF、ICC、不要メタデータは保存プロジェクトへコピーしない。
検証:
- 拡張子の許可リスト確認。
- MIMEタイプは参考情報としてのみ扱う。
- ファイルシグネチャ確認。
- Rust側または安全な画像デコーダで実デコードする。
- デコード後にRGBAへ正規化する。
- ファイル名は表示用と内部保存名を分離し、内部保存名はUUIDにする。
7.2 パーツ編集
パーツ種別:
- 顔。
- 前髪。
- 横髪。
- 後ろ髪。
- 左目。
- 右目。
- 左眉。
- 右眉。
- 口。
- 首。
- 胴体。
- 左腕。
- 右腕。
- 装飾。
- その他。
編集機能:
- ポリゴン領域作成。
- ブラシ選択と消しゴム。
- 境界ぼかし幅。
- マスク反転。
- パーツ複製。
- 左右ペア設定。
- 表示、ロック、透明度変更。
- 前後順のドラッグ並べ替え。
半自動機能:
- 透明度境界から初期領域を抽出。
- 色差とエッジから候補領域を作る。
- 顔、目、口の候補検出は任意機能とする。
- 自動候補は必ずユーザー確認後に適用する。
7.3 メッシュ編集
メッシュ仕様:
- 各パーツは独立した2D三角形メッシュを持つ。
- 頂点座標は画像ローカル正規化座標
0.0..1.0とキャンバス座標の両方を扱える。 - UVは元画像のRGBAテクスチャを参照する。
- 境界頂点はパーツマスク境界に沿う。
- 内部頂点密度はパーツ面積、曲率、ユーザー指定密度から決定する。
操作:
- 自動メッシュ生成。
- 頂点追加、削除、移動。
- 辺分割。
- 三角形の再生成。
- 制御点追加。
- 重みペイント。
- メッシュ品質検査。
自動メッシュ生成の実装:
- 初期版は
earcutを採用候補とし、ポリゴン領域と穴あきポリゴンを三角形分割する。 earcutはISCライセンスであることをロックファイルとライセンス出力で確認する。earcutは制約付きDelaunayではないため、三角形品質が不足するパーツでは、分割後に長辺分割、細長三角形の警告、手動頂点編集で補正する。- 制約付きDelaunayライブラリへ変更する場合は、採用前にライセンス、保守状況、WASM有無、CSP互換性をレビューする。
- CDNから三角形分割ライブラリを読み込んではならない。
品質検査:
- 面積0の三角形を禁止。
- 自己交差を警告。
- 極端に細い三角形を警告。
- UV範囲外参照を禁止。
- パーツ領域外の頂点を警告。
7.4 リグ編集
パラメータ:
| ID | 表示名 | 範囲 | 既定値 | 用途 |
|---|---|---|---|---|
angle_x | 顔角度X | -30..30 | 0 | 左右向き |
angle_y | 顔角度Y | -30..30 | 0 | 上下向き |
angle_z | 顔角度Z | -30..30 | 0 | 傾き |
eye_l_open | 左目開閉 | 0..1 | 1 | まばたき |
eye_r_open | 右目開閉 | 0..1 | 1 | まばたき |
mouth_open | 口開閉 | 0..1 | 0 | 発話 |
mouth_smile | 笑顔 | 0..1 | 0 | 表情 |
breath | 呼吸 | 0..1 | 0.5 | 胴体上下 |
hair_sway_x | 髪揺れX | -1..1 | 0 | 横揺れ |
hair_sway_y | 髪揺れY | -1..1 | 0 | 縦揺れ |
変形方式:
- パラメータごとにキー値を持つ。
- キー値ごとに頂点差分、制御点差分、ボーン姿勢を保存する。
- 実行時は範囲内で線形補間または三次補間する。
- MVPでは各パラメータ単独操作の品質を必須とし、複数パラメータ同時適用は
顔角度X/Yのみ受け入れ基準に含める。 - 複数パラメータの同時適用は単純加算を既定としない。
顔角度X/Yのような破綻しやすい組み合わせは、2Dブレンドグリッドまたは補正キーを使う。 - 補正キーが未実装の組み合わせは、UI上で「単独編集のみ」または「プレビュー品質未保証」として扱い、MVP完了条件に含めない。
ボーン:
- パーツ単位または複数パーツ横断の2Dボーンを定義できる。
- ボーンは位置、回転、スケール、親子関係を持つ。
- 頂点は最大4ボーンまでの重みを持てる。
- 初期版ではIKは任意機能とする。
物理:
- 髪、装飾、胸元、袖などに簡易ばね物理を設定できる。
- 入力は顔角度、頭の速度、呼吸、ランダム微動。
- 物理計算は固定時間ステップで安定化する。
- パラメータ範囲外に暴走しないようクランプする。
7.5 入力連動
入力種別:
- マウス位置。
- キーボードショートカット。
- ゲームパッド。
- マイク音量。
- Webカメラ顔トラッキング。
- 外部入力APIは後続版で検討する。
顔トラッキング:
- ユーザーが
カメラを使用を有効にした場合のみ起動する。 - 初回起動時にOS権限ダイアログを表示する。
- 映像フレームはメモリ上で処理し、保存しない。
- デバッグ録画は初期版では実装しない。
- 推論モデルはアプリ同梱またはユーザーが明示的に指定したローカルファイルのみ使用する。
- CDNからモデルを取得しない。
- MediaPipeを使う場合、
.taskモデルは実装前にライセンスと再配布可否を確認し、同梱可能な場合のみsrcまたはアプリリソース内の固定パスから読み込む。 - モデルを同梱できない場合、顔トラッキング機能は無効化し、ユーザーに追加ダウンロードを促す実装も初期版では行わない。
マッピング:
- 入力値は正規化してパラメータへ割り当てる。
- 感度、反転、デッドゾーン、平滑化を設定できる。
- すべての入力連動はプレビュー画面で一時停止できる。
7.6 プレビューと実行時性能
目標:
- 1920 x 1080キャンバス、20パーツ、合計20,000頂点で60 FPSを最終目標とする。
- 顔トラッキング有効時は30 FPS以上を必須、60 FPSを目標。
- 入力から描画反映までの遅延は100 ms未満を目標。
- MVPの必須性能は、1920 x 1080キャンバス、10パーツ、合計5,000頂点で60 FPSとする。
描画:
- PixiJSでパーツごとにメッシュ描画する。
- パーツ順、マスク、透明度、乗算色、スクリーン色を適用する。
- M0から描画負荷を計測し、M3時点で5,000頂点、M4時点で20,000頂点のベンチマークを取る。
- WebGLコンテキストロストに対応し、復旧できなければ日本語エラーを表示する。
変形計算:
- MVPでは頂点差分補間、ボーン行列、物理値の評価をCPUで行ってよい。ただし5,000頂点60 FPSを満たすこと。
- 20,000頂点60 FPSを達成できない場合、頂点差分補間とボーン変形をWeb Workerへ移す。
- Web Workerでも不足する場合、PixiJSカスタムシェーダーまたはWebGL transform feedback相当の方式を検討する。
- GPUシェーダー方式を採用する場合、CSPに
unsafe-evalを追加してはならない。 - 変形パイプラインは、入力正規化、パラメータ補間、ボーン評価、頂点差分合成、物理揺れ、GPU転送の各処理時間を計測できるようにする。
7.7 保存形式
プロジェクト拡張子:
.motion2dproj
形式:
- ZIPコンテナ。
manifest.json。assets/source.pngまたはassets/source.webp。parts/*.json。meshes/*.json。rig/*.json。settings.json。licenses/THIRD_PARTY_NOTICES.md。
禁止:
- 絶対パス保存。
- OSユーザー名保存。
- カメラ画像保存。
- 任意スクリプト同梱。
- 外部URLからの実行時読み込み。
settings.jsonに保存するもの:
- キャンバス表示設定。
- 入力マッピング設定。
- 感度、反転、デッドゾーン、平滑化。
- プレビュー品質設定。
- UIレイアウト。
settings.jsonに保存しないもの:
- カメラ、マイクの有効状態。
- OS権限の許可状態。
- 最近使った絶対パス。
- デバイス固有ID。
- 外部通信の同意状態。
カメラ、マイク、外部通信の許可はアプリ設定として端末ローカルに保存してよいが、プロジェクトファイルには含めない。プロジェクトを開いただけでカメラやマイクが自動起動してはならない。
7.8 ランタイム書き出し
初期版の書き出し:
.motion2dpkgとしてZIPコンテナを書き出す。- ランタイムに必要な画像、メッシュ、リグ、ライセンス情報を含む。
- 任意コードは含めない。
- 読み込み側ランタイムもMITで提供する。
動画書き出しは後続版で対応する。対応時はローカルエンコードのみとし、FFmpeg等を同梱する場合はライセンス確認を必須とする。
8. データモデル
8.1 manifest.json
{
"format": "motion2dproj",
"formatVersion": 1,
"appVersion": "0.1.0",
"createdAt": "2026-05-13T00:00:00Z",
"updatedAt": "2026-05-13T00:00:00Z",
"canvas": {
"width": 2048,
"height": 2048,
"origin": "center"
},
"assets": [
{
"id": "asset_source",
"path": "assets/source.png",
"sha256": "hex-encoded-sha256",
"mime": "image/png"
}
]
}
8.2 part
{
"id": "part_face",
"name": "顔",
"type": "face",
"visible": true,
"locked": false,
"drawOrder": 100,
"opacity": 1,
"mask": {
"type": "polygon",
"points": [[0.4, 0.2], [0.6, 0.2], [0.7, 0.6], [0.3, 0.6]],
"feather": 2
},
"meshId": "mesh_face"
}
8.3 mesh
{
"id": "mesh_face",
"partId": "part_face",
"vertices": [
{ "id": 0, "position": [0.5, 0.3], "uv": [0.5, 0.3] }
],
"triangles": [[0, 1, 2]],
"weights": [
{ "vertexId": 0, "bones": [{ "boneId": "bone_head", "weight": 1.0 }] }
]
}
weightsの要件:
- 1頂点に割り当てられるボーンは最大4件。
- 各頂点のウェイト合計は保存時に1.0へ正規化する。
- 合計が0、負数、NaN、Infinityを含むウェイトは拒否する。
- 正規化による変形差が大きい場合はユーザーに警告する。
8.4 rig
{
"parameters": [
{
"id": "angle_x",
"name": "顔角度X",
"min": -30,
"max": 30,
"default": 0
}
],
"deformers": [
{
"id": "def_face_angle_x",
"targetMeshId": "mesh_face",
"parameterId": "angle_x",
"keys": [
{ "value": -30, "vertexDeltas": [[0, -0.02, 0.0]] },
{ "value": 0, "vertexDeltas": [] },
{ "value": 30, "vertexDeltas": [[0, 0.02, 0.0]] }
]
}
]
}
9. セキュリティ仕様
9.1 基本方針
- ローカルファースト。既定で外部通信なし。
- 画像、カメラ、マイク、プロジェクトはユーザーの端末内で処理する。
- Tauriのcapabilitiesでフロントエンドから呼べる権限を最小化する。
- CSPを有効化し、
unsafe-eval、リモートスクリプト、CDNスクリプトを禁止する。 - ファイル操作はRust側で検証し、フロントエンドから任意パスを直接扱わない。
9.2 ファイル入力対策
必須対策:
- 許可拡張子は
.png、.webpのみ。 - ファイルシグネチャを確認する。
- デコード前にサイズ上限を確認する。
- デコード後に寸法と総ピクセル数を確認する。
- 画像はRGBAへ再エンコードして保存し、余計なメタデータを破棄する。
- ZIPプロジェクト読み込み時はZip Slip対策として、展開先正規化後に作業ディレクトリ外へ出ないことを確認する。
- ZIP内の総展開サイズ、ファイル数、圧縮率を制限し、ZIP爆弾を拒否する。
- ファイル名は表示用以外に使わず、内部IDはUUIDとする。
拒否条件:
- 拡張子とシグネチャが一致しない。
- デコードに失敗する。
- 上限を超える。
- ZIPに絶対パス、
..、制御文字、予約デバイス名が含まれる。 - プロジェクト内JSONがスキーマ検証に失敗する。
9.3 Tauri権限
dialog:openは画像とプロジェクト選択に限定する。fs権限はアプリデータディレクトリと、ユーザーがダイアログで選択した保存先に限定する。shell権限は既定で無効。http権限は既定で無効。- リモートURLへTauri APIを公開しない。
- 複数ウィンドウを使う場合、権限の高いウィンドウとプレビュー用ウィンドウを分離する。
9.4 CSP
推奨CSP:
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
img-src 'self' asset: blob: data:;
media-src 'self' blob:;
connect-src 'self';
font-src 'self';
object-src 'none';
base-uri 'none';
frame-ancestors 'none';
style-src 'unsafe-inline'はUIライブラリ都合で初期許容とする。可能ならnonce方式へ移行する。script-srcにunsafe-evalを入れてはならない。
CSP互換性の検証:
- M0でPixiJS、earcut、Tauri IPCが上記CSPで動作することを確認する。
- ONNX Runtime WebまたはMediaPipeを採用する場合、WASMとWebGPU/WebGLバックエンドが
unsafe-evalなしで動作することをM1までに確認する。 unsafe-evalが必要な依存やビルド設定は採用不可とする。- Vite、minifier、devtool設定が本番ビルドでeval系コードを生成しないことをCIで確認する。
9.5 カメラとマイク
- 初期状態は無効。
- UIで明示的に有効化する。
- カメラ使用中は画面上に状態表示する。
- 映像、音声、推論特徴量を保存しない。
- クラッシュログにカメラフレーム、音声サンプル、顔特徴点を含めない。
9.6 外部通信
初期版では外部通信を実装しない。更新確認、モデルダウンロード、クラッシュ報告、利用統計はすべて非搭載とする。
将来追加する場合:
- 既定は無効。
- 明示的な同意画面を用意する。
- 送信内容を日本語で表示する。
- 送信前にユーザーが確認できる。
- プライバシーポリシーを同梱する。
9.7 ログ
ログに含めてよいもの:
- アプリバージョン。
- OS種別。
- 処理時間。
- エラーコード。
ログに含めてはならないもの:
- 画像内容。
- カメラ、マイクデータ。
- 絶対パス。
- OSユーザー名。
- 入力ファイル名の完全値。
- プロジェクト内の任意テキスト。
9.8 依存関係とサプライチェーン
リリース前に必須:
- npmとCargoのロックファイルをコミットする。
npm audit、cargo audit、cargo deny相当のチェックを実行する。- 依存ライセンス一覧を生成する。
- 禁止ライセンスが含まれたらビルド失敗にする。
- 直接依存はバージョン範囲を広げすぎない。
- CDN配信スクリプトは禁止。
- postinstallで任意バイナリ取得する依存はレビュー必須。
- モデルファイルはSHA-256を固定する。
9.9 セキュリティ受け入れ基準
以下をすべて満たすまでリリース不可:
- 悪意ある拡張子、二重拡張子、MIME偽装を拒否するテストがある。
- 壊れたPNG/WebPでクラッシュしない。
- 巨大画像でメモリ枯渇しない。
- Zip Slip、ZIP爆弾、JSON過大入力を拒否する。
- CSP違反がない。
- Tauri capabilitiesで不要権限がない。
- 依存脆弱性にCritical、Highがない。
- 禁止ライセンスがない。
- 外部通信が既定で発生しないことを確認する。
- カメラとマイクが無効状態で起動する。
10. ライセンス仕様
10.1 アプリ本体
- ルートに
LICENSEを置き、MIT License全文を含める。 - ソースコード、ドキュメント、サンプルプロジェクトはMITとする。
- ユーザーが読み込んだ画像、作成したプロジェクト、書き出した成果物の権利はユーザーに帰属する。
- サンプル画像を同梱する場合、MIT、CC0、自作のいずれかに限定する。
10.2 禁止ライセンス
- GPL。
- AGPL。
- LGPL。
- SSPL。
- Commons Clause。
- 商用利用制限、再配布制限、用途制限付きモデル。
- Live2D Cubism SDKなど独自契約が必要なSDK。
10.3 NOTICE
- Apache-2.0依存がある場合、ライセンス文とNOTICEを同梱する。
- Viteのライセンス出力機能、npmライセンス生成、Cargoライセンス生成をCIで使う。
- 書き出しランタイムには必要な第三者ライセンスのみ含める。
11. 実装設計
11.1 ディレクトリ案
motion2d/
LICENSE
README.md
docs/
live2d_like_single_image_app_spec.md
threat_model.md
security_checklist.md
package.json
src/
app/
components/
features/
import/
parts/
mesh/
rig/
preview/
export/
lib/
styles/
src-tauri/
Cargo.toml
capabilities/
src/
commands/
image_validation.rs
project_io.rs
zip_guard.rs
runtime/
web/
README.md
tests/
11.2 フロントエンド責務
- UI表示。
- 編集状態管理。
- PixiJSキャンバス描画。
- パラメータ編集。
- 入力デバイス値の正規化。
- Rustコマンド呼び出し。
11.3 Rust側責務
- ファイル選択結果の検証。
- 画像デコードとRGBA正規化。
- プロジェクトZIPの安全な読み書き。
- JSONスキーマ検証。
- SHA-256計算。
- ログの匿名化。
- OS固有保存先の管理。
11.4 レンダリングパイプライン
- プロジェクト読み込み。
- テクスチャをGPUへアップロード。
- パーツ順でメッシュを生成。
- 現在パラメータを評価。
- ボーン変形、頂点差分、物理揺れを適用。
- マスクと合成を適用。
- キャンバスへ描画。
11.5 状態管理
状態は以下に分離する。
- 永続状態: プロジェクトに保存するデータ。
- 一時状態: 選択中ツール、ズーム、表示状態。
- 実行時状態: 入力値、物理速度、FPS。
- セキュリティ状態: 権限許可、カメラ使用中、外部通信設定。
12. UI仕様
12.1 共通
- UIテキストは日本語。
- アイコンボタンにはツールチップを付ける。
- 破壊的操作は確認ダイアログを出す。
- 保存前の未保存変更は画面遷移時に警告する。
- エラーは原因、対処、詳細表示の3段階にする。
12.2 エラーメッセージ例
| 状況 | 表示 |
|---|---|
| 非対応ファイル | このファイル形式は読み込めません。PNGまたはWebPを選択してください。 |
| サイズ超過 | 画像が大きすぎます。8192 x 8192 px以下の画像を選択してください。 |
| 壊れた画像 | 画像を読み込めませんでした。ファイルが破損している可能性があります。 |
| 権限なし | 保存先に書き込めません。別の場所を選択してください。 |
| カメラ拒否 | カメラを使用できません。OSの権限設定を確認してください。 |
12.3 ショートカット
| 操作 | 既定 | 有効画面 | 補足 |
|---|---|---|---|
| 保存 | Ctrl/Cmd + S | 全画面 | テキスト入力中も保存を優先 |
| 元に戻す | Ctrl/Cmd + Z | 編集画面 | テキスト入力中は文字入力の取り消しを優先 |
| やり直し | Ctrl/Cmd + Shift + Z | 編集画面 | テキスト入力中は文字入力のやり直しを優先 |
| 手のひら | Space長押し | パーツ編集、メッシュ編集、リグ編集 | 押下中のみパンツールへ一時切替 |
| ズームイン | Ctrl/Cmd + + | キャンバス表示画面 | テキスト入力中は無効 |
| ズームアウト | Ctrl/Cmd + - | キャンバス表示画面 | テキスト入力中は無効 |
| プレビュー再生 | Space | プレビュー画面 | テキスト入力中は無効。編集画面では手のひらを優先 |
画面上の表示は保存、元に戻すなど日本語にする。
13. テスト仕様
13.1 単体テスト
- 画像検証。
- ZIP安全展開。
- JSONスキーマ検証。
- メッシュ品質検査。
- パラメータ補間。
- 物理計算の安定性。
- ライセンス許可リスト判定。
- ボーンウェイト正規化。
- 入力マッピング設定の保存と再読み込み。
13.2 結合テスト
- PNG読み込みからプロジェクト保存まで。
- プロジェクト再読み込みで表示が一致する。
- パーツ作成、メッシュ生成、パラメータ変形がプレビューに反映される。
- カメラ無効時にカメラアクセスが発生しない。
- カメラ有効時に保存ファイルへ映像が含まれない。
13.3 E2Eテスト
- 新規作成。
- 画像読み込み。
- パーツ追加。
- 自動メッシュ生成。
- 顔角度Xのキー作成。
- プレビューでスライダー操作。
- 保存。
- 再起動後にプロジェクトを開く。
- 入力マッピング、感度、反転、平滑化が再読み込み後も保持される。
13.4 セキュリティテスト
- 拡張子偽装。
- MIME偽装。
- 壊れた画像。
- 巨大画像。
- ZIP爆弾。
- Zip Slip。
- 巨大JSON。
- CSP違反。
- 外部通信検出。
- 依存脆弱性検出。
- ONNX Runtime Web、MediaPipe、モデルファイルのライセンス棚卸し。
14. CI/CD
必須ジョブ:
- 型チェック。
- フォーマット確認。
- lint。
- フロントエンド単体テスト。
- Rust単体テスト。
- E2Eテスト。
- 依存脆弱性チェック。
- ライセンスチェック。
- ビルド。
- 成果物署名準備。
リリースブロッカー:
- テスト失敗。
- CriticalまたはHigh脆弱性。
- 禁止ライセンス。
- CSP緩和。
- 不要Tauri権限。
- 外部通信の追加。
- 未審査モデルファイルの追加。
15. 実装マイルストーン
M0: 基盤
- Tauri + React + TypeScript + Viteの初期化。
- MIT License追加。
- 日本語UI基盤。
- CSPとcapabilitiesの最小設定。
- CIで型チェック、lint、テスト、ライセンスチェック。
- PixiJS、earcut、Tauri IPCのCSP互換確認。
- ONNX Runtime WebまたはMediaPipeを使う場合は、
unsafe-evalなしのWASM動作確認用スパイクを作る。
完了条件:
- アプリが起動する。
- 不要な外部通信がない。
- セキュリティチェックが通る。
- 本番ビルドのCSPに
unsafe-evalがない。 - 採用予定の推論ランタイムとモデルファイルのライセンス審査結果が記録されている。未確定の場合、推論機能はMVP範囲外として扱う。
M1: 安全な画像読み込み
- PNG/WebP読み込み。
- シグネチャ検証。
- サイズ制限。
- RGBA正規化。
- PixiJS表示。
完了条件:
- 正常画像が表示できる。
- 悪意あるファイルを拒否するテストが通る。
M2: パーツ編集
- ポリゴン領域作成。
- パーツ一覧。
- 表示、ロック、前後順。
- マスク表示。
完了条件:
- 複数パーツを作り、前後順で表示できる。
M3: メッシュ編集
- 自動メッシュ生成。
- 頂点編集。
- メッシュ品質検査。
- UV描画。
- 5,000頂点と20,000頂点の描画パイプライン負荷測定。
完了条件:
- パーツがメッシュで描画され、頂点移動で変形する。
- 5,000頂点で60 FPSを満たす。
- 20,000頂点でのFPS、CPU時間、GPU時間、メモリ使用量を記録する。
M4: リグ編集
- パラメータ作成。
- キー追加。
- 頂点差分保存。
- 補間プレビュー。
顔角度X/Y同時操作の補正方式を実装する。MVPで未実装にする場合は、同時操作をMVP完了条件から外しv0.2課題として明記する。- 20,000頂点の変形計算負荷測定。
完了条件:
- 顔角度X、顔角度Y、目開閉、口開閉がスライダーで動く。
- MVPに
顔角度X/Y同時操作を含める場合、同時操作で顔メッシュが破綻しない。 - 20,000頂点で60 FPS未満の場合、Web WorkerまたはGPU移行の設計判断を記録する。
M5: 入力連動
- マウス連動。
- 音声音量連動。
- カメラ顔トラッキング。採用ゲートを通過した場合のみ実装し、未通過の場合はv0.2へ延期する。
- 感度、反転、平滑化設定。
- 入力マッピング、感度、反転、デッドゾーン、平滑化の保存と再読み込み。
完了条件:
- 顔トラッキングをM5に含める場合、カメラ入力で顔角度、目、口が動く。
- カメラ無効時にアクセスが発生しない。
- 入力設定が
.motion2dprojのsettings.jsonへ保存され、再読み込み後に復元される。 - カメラ、マイクの有効状態はプロジェクトへ保存されず、プロジェクトを開いても自動起動しない。
M6: 保存と書き出し
.motion2dproj保存。- 再読み込み。
.motion2dpkg書き出し。- ライセンス情報同梱。
完了条件:
- 保存、再読み込み、ランタイム書き出しができる。
- プロジェクトに禁止データが含まれない。
16. レビュー観点
16.1 実装レビュー
- 仕様にない外部通信がないか。
- UI文字列が日本語か。
- ファイル検証がRust側で行われているか。
- フロントエンドが任意パスを扱っていないか。
- レンダリング負荷が目標内か。
- 保存形式がスキーマ通りか。
16.2 セキュリティレビュー
- ファイル入力の攻撃面。
- ZIP処理。
- JSON過大入力。
- Tauri権限。
- CSP。
- カメラ、マイクの扱い。
- ログ。
- 依存関係。
16.3 ライセンスレビュー
- アプリ本体がMITか。
- 依存関係に禁止ライセンスがないか。
- Apache-2.0のNOTICEが同梱されているか。
- モデルファイルの再配布権が明確か。
- サンプル画像の権利が明確か。
17. 未決定事項
実装開始前に決めるべき項目:
- 顔トラッキングにMediaPipeを使うか、ONNXモデルを同梱するか。
- 初期版でJPEGを許可するか。
- Linuxを正式対応に含めるか。
- 動画書き出しを初期版に含めるか。
- 自動パーツ候補にどの程度のAI処理を含めるか。
- ONNX Runtime Webの採用可否。実際のnpm配布物、WASM、ThirdPartyNoticesを確認して決める。
- MediaPipe
.taskモデルのオフライン同梱可否。ライセンス、再配布条件、SHA-256、同梱手順を確定する。 顔角度X/Y同時操作をMVPに含めるか、v0.2へ延期するか。
推奨判断:
- 顔トラッキングは初期版では採用保留とする。MediaPipeを使う場合は、npmパッケージ、WASM、
.taskモデルのライセンス確認、NOTICE同梱、オフライン同梱手順、CSP互換確認を実装前に完了する。 - JPEGは初期版では非対応または警告付き対応にする。
- Linuxはベータにする。
- 動画書き出しは後続版に回す。
- 自動パーツ候補は透明度、色差、エッジベースに留め、AI自動分割は後続版にする。
- MVPは推論ランタイムなしで成立させる。顔トラッキングはライセンスとCSPが確定した場合のみM5へ含める。
- 三角形分割は
earcutを初期候補にする。
18. 実装着手チェックリスト
LICENSEにMIT Licenseを追加した。docs/security_checklist.mdを作成した。docs/threat_model.mdを作成した。- 禁止ライセンス一覧をCIに設定した。
- Tauri capabilitiesの最小権限設計を作成した。
- CSPを設定した。
- 画像読み込み制限値を定数化した。
.motion2dprojJSONスキーマを作成した。- セキュリティテスト用の悪性サンプルを安全な形で用意した。
- UI文字列の日本語固定ルールをlintまたはレビュー項目に入れた。
- ONNX Runtime Web、MediaPipe、モデルファイルの採用可否を
licenses/dependency_review.mdへ記録した。 earcutのライセンスとバージョンをロックした。settings.jsonへ保存する項目と保存しない項目のスキーマを定義した。
19. 参考情報
- Tauri capabilities: https://v2.tauri.app/security/capabilities/
- Tauri permissions: https://v2.tauri.app/security/permissions/
- Tauri CSP: https://tauri.app/ja/security/csp/
- OWASP File Upload Cheat Sheet: https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html
- PixiJS License: https://github.com/pixijs/pixijs/blob/dev/LICENSE
- three.js License: https://github.com/mrdoob/three.js/blob/dev/LICENSE
- ONNX Runtime License: https://github.com/microsoft/onnxruntime/blob/main/LICENSE
- ONNX Runtime ThirdPartyNotices: https://github.com/microsoft/onnxruntime/blob/main/ThirdPartyNotices.txt
- Tauri License: https://github.com/tauri-apps/tauri/blob/dev/LICENSE_MIT
- Tauri Apache-2.0 License: https://github.com/tauri-apps/tauri/blob/dev/LICENSE_APACHE-2.0
- Rust License Policy: https://www.rust-lang.org/policies/licenses/
- Vite license output: https://vite.dev/guide/features.html
- earcut License: https://github.com/mapbox/earcut
- MediaPipe Face Landmarker Web: https://ai.google.dev/edge/mediapipe/solutions/vision/face_landmarker/web_js
20. MVPの最小実装範囲
レビュー後に実装へ進める最小範囲は以下とする。
- Tauriデスクトップアプリ。
- PNG/WebP読み込み。
- 手動パーツ分割。
- 自動メッシュ生成。
- 頂点移動による変形キー作成。
- スライダーによるリアルタイムプレビュー。
- マウス入力による顔角度連動。
.motion2dproj保存と再読み込み。- セキュリティチェック、ライセンスチェック、テスト一式。
カメラ顔トラッキング、音声連動、物理揺れ、ランタイム書き出しはMVP後半またはv0.2で実装してよい。特にカメラ顔トラッキングは、MediaPipeまたはONNXモデルのライセンス、オフライン同梱、CSP互換、外部通信なしの条件を満たすまでMVP必須範囲に含めない。