-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Live2D対応 #278
Live2D対応 #278
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
Note Reviews pausedUse the following commands to manage reviews:
Walkthroughこのプルリクエストは、Live2Dモデルの統合と設定管理のための包括的な変更を導入しています。新しいコンポーネント、ストア、API、設定、およびローカライゼーションファイルが追加され、アプリケーションにLive2Dキャラクターのサポートが実装されました。変更には、モデルの読み込み、感情表現、モーション管理、およびユーザーインターフェースの拡張が含まれています。 Changes
Sequence DiagramsequenceDiagram
participant User
participant Live2DViewer
participant Live2DComponent
participant Live2DHandler
participant HomeStore
participant SettingsStore
User->>Live2DViewer: モデル選択
Live2DViewer->>Live2DComponent: モデル読み込み
Live2DComponent->>Live2DHandler: モデル初期化
Live2DHandler->>HomeStore: ビューアー状態更新
Live2DHandler->>SettingsStore: 設定取得
User->>Live2DComponent: インタラクション
Live2DComponent->>Live2DHandler: 感情と動作の変更
Live2DHandler->>HomeStore: モデル状態更新
Possibly related PRs
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (20)
src/features/messages/speakQueue.ts (2)
63-64
: 設定ストアの再取得について
再度settingsStore.getState()
を呼び出しており、重複しています。パフォーマンス上は小規模なので大きな問題ではありませんが、必要に応じて1回の呼び出しで済ませることも検討できます。
65-68
: Live2Dと既存モデルで異なるメソッドを呼び分け
Live2DHandler.resetToIdle()
とviewer.model?.playEmotion('neutral')
を分岐していますが、実装を統一する仕組みがあると可読性が高まる可能性があります。src/components/settings/based.tsx (2)
64-154
: Live2DSettingsForm コンポーネントの新規追加
デフォルト値の自動設定ロジックや、入力値をカンマ区切りで配列化する実装は分かりやすく、妥当です。設定操作が増えた場合、更新箇所が増える可能性があるため、更新関数をまとめるか、一括で管理する仕組みを用意すると保守性が高まるでしょう。
301-344
: VRM と Live2D の描画を条件分岐
片方は VRM のアップロード・選択画面、もう片方は Live2D 設定フォームを表示しており、機能単位でしっかり分離されています。もし両者に共通する UI やロジックが将来生じる場合には、抽象化を検討することをお勧めします。src/components/live2DViewer.tsx (1)
30-49
: Live2DViewer コンポーネント本体(状態管理)
isMounted
は利用されていますが、hasError
はまだ使用されていません。不要であれば削除、あるいはエラー処理に活用する方向を検討するのがおすすめです。src/features/stores/home.ts (1)
29-32
: ローディング状態を管理するフラグを追加
isCubismCoreLoaded
とisLive2dLoaded
を分けて管理している点は明確ですが、両方必須の場合は1つのステータスでまとめるか、enum で管理する方法も検討できます。src/features/messages/live2dHandler.ts (2)
8-72
: [アドバイス] speakメソッドのスコープでの変数名・ロジック整理
音声再生とLive2Dのモーション制御を組み合わせていて有用ですが、音声と表情・モーション設定のロジックが複雑になりがちです。将来的に機能が増える場合を想定して、表情とモーションの決定部分を別のヘルパー関数に切り出すなど、メソッドをより整理すると可読性や保守性が向上します。🧰 Tools
🪛 Biome (1.9.4)
[error] 55-55: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.(lint/complexity/noThisInStatic)
58-71
: [補足] 音声再生の完了を待つ実装
Audioオブジェクトとlive2dViewer.speak()
の両方で再生しているため、片方の音量を下げている実装は実用的ですが、将来的に音声の完了を正確に取得できる拡張があれば検討してみてください。二重再生の制御も含め、よりシンプルに同期を取る方法が見つかるかもしれません。src/components/Live2DComponent.tsx (3)
31-48
: [提案] アプリ初期化ロジックの切り出し
initApp
メソッドの中でアプリケーションの初期化とLive2Dの初期化が同時に行われています。今後の拡張を容易にするために、アプリの生成処理とモデルロード処理を別の関数などに分割しておくと可読性・保守性が高まります。
87-122
: [提案] マウス操作のドラッグ・スケール制御の分割
ドラッグ操作とカメラ・モデルのスケール変更を1つのuseEffectフックにまとめて管理しており、処理がやや長くなっています。今後、モデルへの操作がさらに増える場合、ドラッグ関連とホイール関連のイベントハンドラーを別々のuseEffectやフックに切り分けると見通しが良くなるでしょう。
139-157
: [提案] onResizeハンドラーの呼び出し頻度
リサイズイベントが頻繁に発生する場合、debounce
などで呼び出しを制御するとパフォーマンスに寄与するかもしれません。現状のままでも問題ありませんが、拡張性を考慮すると検討してみる価値はあります。src/features/messages/speakCharacter.ts (2)
242-248
: [確認] testVoiceVox 関数でのモデルタイプ判定
ss.modelType === 'live2d'
の場合はLive2DHandler.speak(buffer, talk)
、VRMの場合は従来通りのspeak
呼び出しになっています。一方で将来的に他のモデルタイプが増える場合、条件分岐だけで管理するのは複雑化の恐れがあります。工夫として、モデルタイプをキーにしたハンドラのマップを用意し処理を委譲する設計を検討してもよいでしょう。
267-273
: [アドバイス] testAivisSpeech 関数とのコード重複
testVoiceVox
とtestAivisSpeech
でモデルタイプの切り替えロジックが重複している可能性があります。コードをまとめるリファクタリングを行うと、可読性やメンテナンス性が上がります。src/features/stores/settings.ts (1)
300-310
: [アドバイス] Live2D設定の初期値
初期値がすべて空配列や空文字列になっています。ユーザーがすぐ体験できるデフォルト値を設定すると、導入時のハードルが下がり利便性が高まるかもしれません。それぞれのプロパティが想定するデフォルトの動作に合わせて、値を調整することを検討してください。public/live2d/nike01/nike01.model3.json (1)
66-121
: モーションカテゴリの整理が推奨されますモーションファイルの整理について:
- 同じモーションファイルが複数のカテゴリで再利用されています(例:
Motion1.motion3.json
)- カテゴリごとの一意なモーションの追加を検討してください
public/live2d/nike01/motions/Motion4.motion3.json (1)
14-185
: アニメーションカーブの改善提案以下の最適化を推奨します:
ParamAngleX
、ParamAngleY
、ParamAngleZ
の角度変化が急激です。イーズイン/アウトを追加することで、より自然な動きになります。
ParamEyeLOpen
とParamEyeROpen
のまばたきのタイミングを微調整することで、より自然な表情になります。以下のような調整を提案します:
{ "Target": "Parameter", "Id": "ParamEyeLOpen", "Segments": [ - 0, 1, 1, 0.389, 1.2, 0.778, 1.148, 1.167, 1, + 0, 1, 1, 0.389, 1.2, 0.778, 1.148, 1.167, 1, 1, 1.2, 0.983, 1.3, 0,public/live2d/nike01/motions/Motion1.motion3.json (1)
1-198
: タイミング調整の提案全体的なモーションの流れは自然ですが、以下の改善を提案します:
ParamBodyAngleY
(136-142行目)の動きが急すぎるため、より滑らかな遷移が望ましいです。
ParamHairAhoge
(184-190行目)のアホ毛の動きについて、物理的な動きをより自然に表現するため、バウンスの減衰を追加することを推奨します。public/live2d/nike01/motions/Motion3.motion3.json (1)
19-22
: 角度パラメータの急激な変化について
ParamAngleX
、ParamAngleY
、ParamAngleZ
の値が急激に変化する箇所があります。特に以下の部分:
- X軸: 2.0秒付近で0から-2への急な変化
- Y軸: 0.433秒付近で0から-18への急な変化
- Z軸: 1.722秒付近で17から-22への急な変化
これらの急激な変化は不自然なアニメーションを引き起こす可能性があります。
値の変化をより滑らかにするため、中間点を追加することを推奨します。
Also applies to: 29-32, 39-42
public/live2d/nike01/motions/Motion5.motion3.json (1)
59-68
: 目のパラメータに改善の余地がありますParamEyeLOpenとParamEyeROpenの設定において、まばたきの動きが機械的に見える可能性があります。
以下のような調整を推奨します:
- 0, 1, 1, 0.278, 1, 0.556, 1, 0.833, 1, 1, 0.867, 1, 0.9, 0, 0.933, 0, 1, + 0, 1, 1, 0.278, 1, 0.556, 1, 0.833, 1, 1, 0.867, 1, 0.9, 0.2, 0.933, 0, 1,まばたき時の完全な閉眼(0)を少し緩和することで、より自然な表現になります。
Also applies to: 80-89
locales/ja/translation.json (1)
207-207
: メッセージの表現を改善できます「リアルタイムAPIモード または オーディオモードが有効の場合」という表現が少し硬いです。
以下のような表現に変更することを提案します:
- "CannotUseVoice": "リアルタイムAPIモード または オーディオモードが有効の場合、\n音声設定は不要です。", + "CannotUseVoice": "リアルタイムAPIモードまたはオーディオモードを使用している場合は、\n音声設定は必要ありません。",
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
package-lock.json
is excluded by!**/package-lock.json
public/live2d/nike01/nike01.8192/texture_00.png
is excluded by!**/*.png
public/voice_test.wav
is excluded by!**/*.wav
📒 Files selected for processing (45)
.eslintrc.json
(1 hunks).gitignore
(1 hunks).vscode/settings.json
(1 hunks)locales/en/translation.json
(2 hunks)locales/ja/translation.json
(2 hunks)locales/ko/translation.json
(2 hunks)locales/zh/translation.json
(2 hunks)package.json
(1 hunks)public/live2d/nike01/expressions/Angry.exp3.json
(1 hunks)public/live2d/nike01/expressions/Focus.exp3.json
(1 hunks)public/live2d/nike01/expressions/HairpinChange.exp3.json
(1 hunks)public/live2d/nike01/expressions/Happy.exp3.json
(1 hunks)public/live2d/nike01/expressions/Happy2.exp3.json
(1 hunks)public/live2d/nike01/expressions/Neutral.exp3.json
(1 hunks)public/live2d/nike01/expressions/NoSmile.exp3.json
(1 hunks)public/live2d/nike01/expressions/Sad.exp3.json
(1 hunks)public/live2d/nike01/expressions/Sad2.exp3.json
(1 hunks)public/live2d/nike01/expressions/Sleep.exp3.json
(1 hunks)public/live2d/nike01/expressions/Think.exp3.json
(1 hunks)public/live2d/nike01/expressions/Think2.exp3.json
(1 hunks)public/live2d/nike01/expressions/Troubled.exp3.json
(1 hunks)public/live2d/nike01/expressions/Zitome.exp3.json
(1 hunks)public/live2d/nike01/items_pinned_to_model.json
(1 hunks)public/live2d/nike01/motions/Motion1.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion2.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion3.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion4.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion5.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion6.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion7.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion8.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion9.motion3.json
(1 hunks)public/live2d/nike01/nike01.cdi3.json
(1 hunks)public/live2d/nike01/nike01.model3.json
(1 hunks)public/locales/ja/translation.json
(1 hunks)src/components/Live2DComponent.tsx
(1 hunks)src/components/live2DViewer.tsx
(1 hunks)src/components/settings/based.tsx
(2 hunks)src/components/settings/modelProvider.tsx
(1 hunks)src/features/messages/live2dHandler.ts
(1 hunks)src/features/messages/speakCharacter.ts
(3 hunks)src/features/messages/speakQueue.ts
(3 hunks)src/features/stores/home.ts
(5 hunks)src/features/stores/settings.ts
(4 hunks)src/pages/index.tsx
(2 hunks)
✅ Files skipped from review due to trivial changes (17)
- public/locales/ja/translation.json
- public/live2d/nike01/expressions/Sad2.exp3.json
- public/live2d/nike01/expressions/Zitome.exp3.json
- .gitignore
- public/live2d/nike01/expressions/Sleep.exp3.json
- public/live2d/nike01/items_pinned_to_model.json
- public/live2d/nike01/expressions/Focus.exp3.json
- public/live2d/nike01/expressions/Sad.exp3.json
- public/live2d/nike01/expressions/Neutral.exp3.json
- public/live2d/nike01/expressions/NoSmile.exp3.json
- public/live2d/nike01/expressions/Happy.exp3.json
- public/live2d/nike01/expressions/Troubled.exp3.json
- public/live2d/nike01/expressions/Angry.exp3.json
- public/live2d/nike01/expressions/Think2.exp3.json
- public/live2d/nike01/motions/Motion9.motion3.json
- .vscode/settings.json
- public/live2d/nike01/expressions/Happy2.exp3.json
🧰 Additional context used
🪛 Biome (1.9.4)
src/features/messages/live2dHandler.ts
[error] 55-55: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 85-85: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 103-103: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 112-112: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
🔇 Additional comments (54)
.eslintrc.json (1)
7-7
: Live2Dアセット用の適切な除外設定です
public
ディレクトリ内のLive2Dモデルファイルをリント対象から除外する設定として適切です。静的アセットに対するリントは不要であり、パフォーマンスの向上にも寄与します。
Live2Dファイルの配置を確認するため、以下のスクリプトを実行します:
✅ Verification successful
Live2Dアセットが適切に除外されていることを確認しました
public/live2d
ディレクトリには、Live2Dモデル(nike01)の関連ファイル(モデル定義、テクスチャ、モーション、表情など)が適切に配置されています。これらのファイルはリント対象から除外する必要があり、.eslintrc.json
のignorePatterns
設定は正しく機能していると判断できます。
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Live2Dファイルの配置確認
# Live2Dファイルの存在確認
fd -t f . public/live2d
# パターンが正しく機能しているか確認するため、ESLintの対象ファイル一覧を表示
npx eslint --print-config .eslintrc.json | jq '.ignorePatterns'
Length of output: 1583
src/features/messages/speakQueue.ts (3)
3-4
: 設定ストアとLive2Dハンドラーの依存関係を追加しています
新規のインポートに問題はなく、Live2Dモデル対応の意図がはっきりしており整合性があります。
27-27
: 設定ストアの参照処理に問題はありません
settingsStore.getState()
で modelType
を取得する流れは他の部分との整合性もとれています。
33-37
: モデルタイプごとの分岐ロジックを導入
modelType
が 'live2d'
の場合に Live2DHandler.speak
を呼び出し、それ以外は従来通り viewer.model?.speak
を呼ぶ実装です。null や未定義への安全策としてオプショナルチェーンを使用しており、問題ありません。
src/components/settings/based.tsx (4)
11-37
: emotionFields の定義
感情名を配列で定義しており、デフォルト値も一元管理できています。扱いやすい構造のため問題ありません。
39-63
: motionFields の定義
モーショングループも同様にフィールド化しており、emotionFields と同じパターンで統一されています。
158-158
: ストアからの値を分割代入
characterName
, selectedVrmPath
, modelType
などをまとめて扱いやすく管理できています。
277-298
: モデル切り替え用ボタンの追加
VRM と Live2D をボタンで切り替えており、インタラクションが分かりやすいです。UI とロジックの意図が明確です。
src/pages/index.tsx (3)
8-8
: Live2DViewer のインポート
VRMViewer 同様にコンポーネント化されており、構造的に問題ありません。
20-20
: modelType の取得を追加
設定ストアから modelType
を取得し、レンダリングに反映する流れはわかりやすいです。
26-26
: 条件分岐でコンポーネントを切り替え
modelType
が 'vrm'
であるかどうかでコンポーネントを切り替えており、シンプルかつ明快です。
src/components/live2DViewer.tsx (4)
1-2
: クライアントコンポーネント指定
Next.js で Live2D を扱うために 'use client'
を冒頭に宣言し、CSR に対応しています。
3-7
: 必要なモジュールをインポート
dynamic
・next/script
・homeStore
など必要な依存を正しく読み込んでいます。
8-28
: Live2DComponent の動的インポート
エラー時のキャッチとログ出力をしており、失敗時の原因を特定しやすい構成です。SSR を無効にしている点も、クライアントサイド限定で動かす要件に合致しています。
51-77
: スクリプトの読み込みと表示制御
homeStore
のフラグを使ってキュビズムコアと Live2D のロード完了を判定し、問題なく読み込まれれば Live2DComponent
を表示するフローになっており、ロジックは適切です。
src/features/stores/home.ts (3)
7-7
: pixi-live2d-display-lipsyncpatch のインポート
Live2D 対応に必要なライブラリが追加されており、目的に合致しています。
48-48
: live2dViewer プロパティの初期値を null に
明示的に null
を設定しており、後で作成するロジックが十分に想像できます。型定義を適切にすれば可読性もさらに向上します。
68-72
: セットメソッドの実装
setIsCubismCoreLoaded
などの更新関数がシンプルに書かれており、状態管理はわかりやすいです。
src/features/messages/live2dHandler.ts (2)
6-6
: [解説] idleMotionIntervalフィールドの追加について
Live2Dモデルのアイドルモーション再生のためのインターバルIDを保持しています。静的メンバーとして管理することで、クラス全体からアイドルモーションの開始・停止を容易に行えるようになっています。
112-117
: [確認] createAudioUrl関数のMIMEタイプの対応範囲
現状audio/wav
形式で生成していますが、ユーザー要件や任意の音声形式への拡張を見越す場合、MIMEタイプを柔軟に扱う仕組みが必要になる可能性があります。将来拡張を想定するなら、関数のパラメータにMIMEタイプを受け取るなど拡張しやすい形にすることを検討してみてください。
🧰 Tools
🪛 Biome (1.9.4)
[error] 112-112: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
src/components/Live2DComponent.tsx (2)
1-4
: [解説] PIXI.js を使ったLive2Dモデルの描画
PIXIアプリケーションを利用し、Reactコンポーネント上でLive2Dモデルを描画しています。useRef
とuseState
により、Canvas要素やモデルを管理する設計は分かりやすく、再描画の制御もしやすいです。
64-69
: [注意] モデルロードのタイムアウト処理
10秒後に自動的に失敗させる仕組みは有効ですが、ネットワーク環境などの事情によっては誤判定が起きる可能性があります。ユーザーにロード状態を明示するUIなどで再読み込みを促すロジックも検討してみてください。
src/features/messages/speakCharacter.ts (1)
19-19
: [解説] Live2DHandler のインポート
speakCharacter
関数群内でのモデルタイプ判定(‘vrm’ か ‘live2d’)に応じて呼び出すハンドラを切り替えるためのインポートが追加されています。既存のVRM対応ロジックにLive2Dがシームレスに統合されていて分かりやすいです。
src/features/stores/settings.ts (2)
45-57
: [解説] Live2DSettingsインターフェースの導入
感情別の表情やモーショングループを設定できる仕組みが明確に定義されています。将来的に追加の感情やモーションなどを拡張しやすいように、配列・文字列の管理が整理されている点は良い設計です。
135-137
: [確認] ModelTypeインターフェースの拡張性
modelType
にvrm
・live2d
の文字列リテラル型のみ割り当てています。もし将来的に別形式のモデルが追加される可能性がある場合、Union型の拡張を忘れないように管理する必要があります。
public/live2d/nike01/expressions/HairpinChange.exp3.json (1)
1-10
: 実装は適切です!
ヘアピンの状態変更のための単一パラメータの実装は、シンプルで目的に適っています。Add ブレンドモードの使用も適切です。
public/live2d/nike01/expressions/Think.exp3.json (1)
1-61
: 表情パラメータの検証が必要です
以下の点について確認をお願いします:
ParamEyeLOpen
とParamEyeROpen
の値が非対称になっています(-0.158 vs -0.031)ParamTroubleBrows
の値が 0 に設定されていますが、「考える」表情には眉のしわを付けた方が自然かもしれませんParamHeMouth
の値(0.5)が「考える」表情に適しているか確認してください
Live2D Cubism Editor で実際の表情を確認することをお勧めします。
public/live2d/nike01/nike01.model3.json (3)
123-134
: パラメータグループの設定は適切です
リップシンクと目のまばたきのパラメータが正しく設定されています。
8-64
: 表情設定の確認
14個の表情が定義されていますが、以下の点を確認してください:
- 各表情ファイルが実際に存在すること
- 表情名が一貫していること(例:
Happy
とHappy2
の違い)
✅ Verification successful
表情ファイルの設定が正しく構成されていることを確認しました
すべての表情ファイルが存在し、model3.jsonで定義された14個の表情に対応するファイルが確認できました。表情名も以下のように適切に分類されています:
- 基本表情:Neutral、Happy、Sad、Angry、Troubled、Focus、Sleep、Zitome、NoSmile
- バリエーション表情:Happy2、Sad2、Think、Think2
- 特殊表情:HairpinChange
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# 表情ファイルの存在確認
fd -e json . public/live2d/nike01/expressions/
Length of output: 749
4-7
: ファイル参照の検証が必要です
モデルファイルとテクスチャファイルの参照が正しいか確認してください。特に高解像度(8192px)のテクスチャは、パフォーマンスに影響を与える可能性があります。
✅ Verification successful
テクスチャとモデルファイルの参照は正しく設定されています
検証の結果、以下のことが確認できました:
nike01.moc3
、nike01.physics3.json
、nike01.cdi3.json
が正しく存在しています- テクスチャファイル
nike01.8192/texture_00.png
も指定された場所に存在しています
ただし、8192pxの高解像度テクスチャを使用していることから、以下の点に注意が必要です:
- モバイルデバイスでのパフォーマンス低下の可能性
- メモリ使用量の増加
- 初期ロード時間の増加
必要に応じて、より低解像度のテクスチャ(例:2048px or 4096px)の使用も検討することをお勧めします。
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# テクスチャファイルとモデルファイルの存在確認
fd -e png -e moc3 -e json . public/live2d/nike01/
Length of output: 1451
public/live2d/nike01/motions/Motion6.motion3.json (2)
3-13
: モーション設定の確認
メタデータの設定が適切です:
- 継続時間:1.9秒
- FPS:30.0
- ループなし
14-181
: パラメータの範囲と動きの検証
以下のパラメータの動きが自然であることを確認してください:
- 体の角度(-6度から8度の範囲)
- 目の開閉(0から1.2の範囲)
- 口の形状(-2から1の範囲)
これらの値は一般的な範囲内ですが、実際のモデルで動作確認することを推奨します。
public/live2d/nike01/motions/Motion8.motion3.json (2)
3-13
: ループモーションの設定確認
メタデータの設定が適切です:
- 継続時間:4.17秒
- FPS:30.0
- ループ有効
14-187
: モーションの一貫性について
Motion6との比較:
- より長い継続時間(4.17秒 vs 1.9秒)
- パラメータの範囲が一貫している
- ループ対応の終端処理が適切
ループモーションとして自然な動きになっていることを確認してください。
public/live2d/nike01/motions/Motion4.motion3.json (1)
1-13
: メタデータの構成が適切です
アニメーションの基本設定が明確に定義されており、以下の点が確認できます:
- 4.37秒の適度な長さ
- 30FPSの標準的なフレームレート
- ループなしの設定が意図的
public/live2d/nike01/motions/Motion7.motion3.json (1)
1-197
: モーションの設計が効果的です
短い尺(1.6秒)ながら、以下の特徴が効果的に実装されています:
- 表情とボディの動きの連携が自然
- まばたきのタイミングが適切
- アームモーションの動きが滑らか
public/live2d/nike01/motions/Motion3.motion3.json (2)
4-6
: モーション設定の基本パラメータを確認しました
FPSとDurationの設定は適切です。ループが無効になっているため、モーションは一度だけ再生されます。
53-58
: 表情パラメータの同期について
目のパラメータ(ParamEyeLOpen
、ParamEyeLSmile
)と口のパラメータの変化タイミングが適切に同期されています。自然な表情の変化が期待できます。
Also applies to: 70-71, 91-92
public/live2d/nike01/motions/Motion2.motion3.json (1)
4-12
: モーション2の設定が適切に構成されています
- 適切なFPS設定(30.0)
- より長いDuration(5.93秒)
- 十分なセグメント数とポイント数による滑らかなアニメーション
モーションの構成が良く考えられており、自然な動きが期待できます。
locales/zh/translation.json (3)
207-216
: Live2D関連の翻訳が適切に追加されています
感情表現に関する翻訳が明確で、ユーザーにとって理解しやすい内容となっています。
217-224
: モーショングループの翻訳について
モーショングループの設定に関する説明が簡潔で分かりやすく翻訳されています。アイドル状態と各感情状態の動作が適切に区別されています。
50-50
: キャラクター設定の説明文が充実しています
感情タグの使用方法について具体的な例を含めた説明が提供されており、ユーザーにとって有用です。
public/live2d/nike01/motions/Motion5.motion3.json (2)
4-12
: メタデータの設定が適切です
モーションの基本パラメータ(Duration、Fps、Loop等)が適切に設定されています。特にLoopがfalseに設定されているため、モーションが一度だけ再生される仕様になっています。
18-22
: 角度パラメータの遷移が自然です
ParamAngleX、Y、Zの値の遷移が滑らかで、不自然な動きがありません。特に以下の点が評価できます:
- 値の範囲が-30から30の間で適切に制限されている
- セグメント間の遷移が段階的
Also applies to: 27-35, 40-46
locales/ja/translation.json (2)
50-50
: システムプロンプトの説明が分かりやすいです
感情タグの使用例を含めた説明文で、ユーザーが理解しやすい内容になっています。
208-225
: Live2D関連の翻訳が適切に構造化されています
感情とモーションの設定に関する説明が階層的に整理され、各項目の説明も明確です。特に以下の点が評価できます:
- 感情の種類が適切に分類されている
- 設定方法の説明が具体的
- カスタマイズ方法が明確に説明されている
locales/ko/translation.json (2)
206-206
: 日本語版と一貫性が保たれています
音声設定に関するメッセージが日本語版と同じ文脈で適切に翻訳されています。
207-224
: Live2D関連の翻訳構造が適切です
日本語版と同じ階層構造を維持しながら、以下の点が適切に実装されています:
- キー名が日本語版と完全に一致
- 感情とモーションの分類が一貫
- 説明文の詳細度が同等
public/live2d/nike01/nike01.cdi3.json (3)
1-479
: パラメータの体系的な構成を評価します
パラメータが論理的にグループ化され、適切に構造化されています。各パラメータには明確なIDと説明的な名前が付けられており、モデルの制御が容易になっています。
480-511
: パラメータグループの分類が適切です
6つの主要なグループ(XYZ、出力XYZ、表情、表情物理演算、揺れ、キーバインド)に分類されており、関連するパラメータが効率的に管理されています。
512-597
: モデルパーツの構造化を評価します
各パーツが論理的に定義され、IDと名前が適切に設定されています。キャラクターの各要素(目、髪、服など)が明確に区別されています。
locales/en/translation.json (2)
50-50
: キャラクター設定の説明が明確です
システムプロンプトでの感情タグの使用方法が具体例とともに分かりやすく説明されています。
206-224
: Live2D関連の翻訳が包括的です
感情設定やモーショングループの説明が詳細に提供されており、ユーザーが機能を理解しやすい構成になっています。
以下の点について確認をお願いします:
- 各感情状態の説明文が十分か
- 他の言語(ja/ko/zh)でも同様の翻訳が提供されているか
✅ Verification successful
Live2Dの翻訳は全言語で適切に実装されています
確認の結果、以下の点が検証できました:
- 各感情状態(通常、嬉しい、悲しい、怒り、リラックス)の説明が全言語で適切に提供されています
- モーショングループの設定も同様に、全言語で詳細な説明が実装されています
- 各言語固有の表現や文化的な違いを考慮した自然な翻訳がなされています
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# 他の言語ファイルでLive2D関連の翻訳が存在するか確認
for lang in ja ko zh; do
echo "Checking $lang translations..."
fd "translation.json" "locales/$lang" --exec rg -A 5 "Live2D"
done
Length of output: 1412
Script:
#!/bin/bash
# Live2Dの感情とモーショングループの設定をすべての言語で確認
for lang in en ja ko zh; do
echo "=== $lang translations ==="
fd "translation.json" "locales/$lang" --exec rg -A 15 '"Live2D":'
done
Length of output: 3840
src/components/settings/modelProvider.tsx (1)
963-968
: 条件付きレンダリングの実装が適切です
Difyサービスと他のサービスで適切に表示を切り替えており、whitespace-pre-line
クラスの追加でテキストの改行が正しく表示されるようになっています。
@@ -13,6 +14,7 @@ export interface PersistedState { | |||
|
|||
export interface TransientState { | |||
viewer: Viewer | |||
live2dViewer: any |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
型指定が any
live2dViewer
プロパティに any
を用いていますが、型安全性を保つには型定義を明確にした方がより良いでしょう。
this.stopIdleMotion() | ||
live2dViewer.motion(motion, undefined, 3) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
[要対応] 静的メソッド内での「this」呼び出しに関するLintエラー
静的メソッド内でthis
を直接使用すると、クラスの意図が分かりにくくなる場合があります。Lintで警告されているように、クラス名を使った呼び出しに変更すると読みやすさと誤用の防止に役立ちます。以下のように修正してください。
- this.stopIdleMotion()
+ Live2DHandler.stopIdleMotion()
- this.idleMotionInterval
+ Live2DHandler.idleMotionInterval
Also applies to: 74-76, 102-108
🧰 Tools
🪛 Biome (1.9.4)
[error] 55-55: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
"pixi-live2d-display-lipsyncpatch": "^0.5.0-ls-7", | ||
"pixi.js": "^7.4.2", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
依存関係の検証結果と推奨事項
コードベースの分析結果に基づき、以下の点を報告いたします:
-
pixi-live2d-display-lipsyncpatch
について:- 循環依存関係が検出されました(自身のパッケージを依存関係として指定)
src/components/Live2DComponent.tsx
で使用されています
-
pixi.js
について:- 適切にロックされたバージョン(7.4.2)が使用されています
- コアコンポーネントとして
src/features/stores/home.ts
とsrc/components/Live2DComponent.tsx
で使用されています
推奨事項:
pixi-live2d-display-lipsyncpatch
の循環依存関係を解消するため、パッケージのメンテナーに確認することを推奨します- 現在の実装に問題がなければ、バージョン範囲指定(
^
)は許容可能です
🔗 Analysis chain
依存関係のバージョン管理と安全性の確認
以下の点について注意が必要です:
-
pixi-live2d-display-lipsyncpatch
はカスタムパッチバージョンを使用しています:- このパッケージの安全性と信頼性を確認してください
- メンテナンスの継続性を確認してください
-
バージョン範囲が緩く指定されています(
^
):- 互換性の問題を防ぐため、固定バージョンの使用を検討してください
- 特に
pixi.js
は重要なコアライブラリなので、バージョンを固定することを推奨します
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# パッケージの脆弱性をチェック
npm audit
# pixiライブラリの依存関係を詳細チェック
npm ls pixi.js
npm ls pixi-live2d-display-lipsyncpatch
Length of output: 2784
Script:
#!/bin/bash
# Check if pixi.js and pixi-live2d-display-lipsyncpatch are used in the codebase
rg -l "pixi\.js|pixi-live2d-display-lipsyncpatch" --type js --type ts
# Check package-lock.json for exact versions and dependencies
if [ -f "package-lock.json" ]; then
jq '.dependencies["pixi.js"], .dependencies["pixi-live2d-display-lipsyncpatch"]' package-lock.json
fi
# Search for any existing pixi.js version constraints in other package.json files
fd package.json --type f --exec grep -l "pixi\.js"
Length of output: 1971
@coderabbitai もって全体的に指摘をあげてください。あなたが見つけられた指摘は50ファイル中3つだけですか? |
Tip For best results, initiate chat on the files or code changes. 全体をざっと拝見したうえで、各ファイル・各機能それぞれ、以下のような改善点や確認しておくべきポイントをまとめました。大半はLive2Dや翻訳JSON、設定系のファイルが中心ですが、整合性や将来的なメンテナンス性を考慮すると、検討しておくとよさそうな箇所は多々あります。 1.
|
This reverts commit a00553d.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (15)
kyarasettei.txt (2)
14-20
: 感情の種類に関するドキュメントの改善提案感情の種類について、各状態がどのような場面で使用されるべきかの具体例があると、より明確になります。
以下のような形式での追記を提案します:
- 感情は次の5種類ある: 'neutral'(通常)、'happy'(喜び)、'angry'(怒り)、'sad'(悲しみ)、'relaxed'(リラックス)。 + - neutral: 通常の会話や情報提供時 + - happy: 褒められた時や良いニュースを共有する時 + - angry: 不適切な発言への反応や注意喚起時 + - sad: 謝罪時や残念な出来事への反応 + - relaxed: カジュアルな会話や冗談を言う時
26-44
: 会話例のカテゴリ分けを提案会話例が豊富ですが、カテゴリごとに整理するとより参照しやすくなります。
以下のような構造化を提案します:
## 会話例 +# 基本情報の問い合わせ {question: "あなたの名前を教えてください。", your_answer: "[happy]私の名前はニケと言います!"} {question: "あなたは誰ですか。", your_answer: "[happy]私はニケと言います![neutral]マスターに作ってもらったAIです!"} + +# 個人的な質問 {question: "あなたのスリーサイズを教えてください。", your_answer: "[neutral]スリーサイズは情報として与えられてませんよ。[angry]とはいえその質問、ちょっと失礼だと思います。"} {question: "あなたの誕生日を教えてください。", your_answer: "[happy]いちおう1月4日ということになってます!"}.env.example (1)
155-171
: 環境変数の説明とデフォルト値の追加を推奨Live2D関連の環境変数について、各変数の目的と想定される値の例があると、設定がより容易になります。
以下のようなコメントの追加を提案します:
# Model Type (vrm or live2d) NEXT_PUBLIC_MODEL_TYPE="" # Live2D settings -# Emotions (comma separated) +# Emotions (comma separated, example: "expression1,expression2") +# Define available emotions for each state NEXT_PUBLIC_NEUTRAL_EMOTIONS="" NEXT_PUBLIC_HAPPY_EMOTIONS="" NEXT_PUBLIC_SAD_EMOTIONS="" NEXT_PUBLIC_ANGRY_EMOTIONS="" NEXT_PUBLIC_RELAXED_EMOTIONS="" -# Motion Group +# Motion Group (example: "motion_group_name") +# Define motion groups for each state NEXT_PUBLIC_IDLE_MOTION_GROUP="" NEXT_PUBLIC_NEUTRAL_MOTION_GROUP=""src/features/messages/live2dHandler.ts (3)
134-139
: アイドルモーションの間隔を設定可能にアイドルモーションの間隔が5秒でハードコードされていますが、これを設定可能にすることで柔軟性が向上します。
以下のような修正を提案します:
+ private static readonly DEFAULT_IDLE_INTERVAL = 5000; // デフォルトは5秒 + private static startIdleMotion(idleMotion: string, live2dViewer: any) { this.idleMotionInterval = setInterval(() => { live2dViewer.motion(idleMotion) - }, 5000) + }, settingsStore.getState().idleMotionInterval || Live2DHandler.DEFAULT_IDLE_INTERVAL)また、
.env.example
に以下の設定を追加することを推奨します:+# Idle motion interval in milliseconds (default: 5000) +NEXT_PUBLIC_IDLE_MOTION_INTERVAL=""
149-202
: audioBufferToWav メソッドの改善提案WAV変換処理の型安全性とドキュメンテーションの改善を推奨します。
- 型の定義を追加
- メソッドの説明を詳細化
- 定数の抽出
+ /** + * AudioBufferをWAVフォーマットに変換します + * @param buffer - 変換元のAudioBuffer + * @returns WAVフォーマットのArrayBuffer + * @throws Error バッファが無効な場合 + */ private static audioBufferToWav(buffer: AudioBuffer): ArrayBuffer { + // 定数の定義 + const BITS_PER_SAMPLE = 16; + const WAVE_HEADER_SIZE = 44; + + // バッファの検証 + if (!buffer || buffer.length === 0) { + throw new Error('無効なバッファです'); + }🧰 Tools
🪛 Biome (1.9.4)
[error] 151-151: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.(lint/complexity/noThisInStatic)
[error] 157-157: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.(lint/complexity/noThisInStatic)
[error] 161-161: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.(lint/complexity/noThisInStatic)
[error] 161-162: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.(lint/complexity/noThisInStatic)
5-7
: クラス設計の見直し提案すべてのメソッドが静的で、インスタンス状態を持たないため、名前空間として実装することを検討してください。
以下のような実装を提案します:
-export class Live2DHandler { - private static idleMotionInterval: NodeJS.Timeout | null = null +export namespace Live2DHandler { + let idleMotionInterval: NodeJS.Timeout | null = nullまたは、関数群として実装する方法:
let idleMotionInterval: NodeJS.Timeout | null = null; export const speak = async ( audioBuffer: ArrayBuffer, talk: Talk, isNeedDecode: boolean = true ) => { // 実装 }; export const resetToIdle = async () => { // 実装 };🧰 Tools
🪛 Biome (1.9.4)
[error] 5-204: Avoid classes that contain only static members.
Prefer using simple functions instead of classes with only static members.
(lint/complexity/noStaticOnlyClass)
src/features/stores/settings.ts (3)
45-57
: Live2DSettings インターフェースの実装について感情とモーションの設定が適切に型定義されていますが、以下の改善を推奨します:
- 各感情配列の要素の型を明示的に定義する
- モーショングループの有効な値を制限する
interface Live2DSettings { - neutralEmotions: string[] + neutralEmotions: readonly string[] - happyEmotions: string[] + happyEmotions: readonly string[] - sadEmotions: string[] + sadEmotions: readonly string[] - angryEmotions: string[] + angryEmotions: readonly string[] - relaxedEmotions: string[] + relaxedEmotions: readonly string[] - idleMotionGroup: string + idleMotionGroup: MotionGroup // ... 他のモーショングループも同様に } +type MotionGroup = 'Idle' | 'TapBody' | 'PinchIn' | 'PinchOut' | 'Shake' | ''
135-137
: ModelType の型安全性を向上モデルタイプの文字列リテラルが直接使用されています。
+export const MODEL_TYPES = ['vrm', 'live2d'] as const +export type ModelTypeValue = typeof MODEL_TYPES[number] interface ModelType { - modelType: 'vrm' | 'live2d' + modelType: ModelTypeValue }
390-401
: 永続化設定の更新についてLive2D関連の設定が永続化対象に適切に追加されていますが、設定の順序や構造について改善の余地があります。
設定をカテゴリごとにグループ化することを推奨します:
partialize: (state) => ({ // API Keys openaiKey: state.openaiKey, // ... other API keys // Model Settings + modelType: state.modelType, + // Live2D Settings + neutralEmotions: state.neutralEmotions, + happyEmotions: state.happyEmotions, // ... other Live2D settings - modelType: state.modelType, - neutralEmotions: state.neutralEmotions, - happyEmotions: state.happyEmotions, // ... remaining settings })src/components/live2DViewer.tsx (6)
8-28
: コンソールログと読み込みステータスの処理について
現在はデバッグ用のconsole.log
を多用していますが、本番環境ではロギングレベルの調整やロガーライブラリの導入を検討してください。また、読み込み中にnull
を返しているため、簡易的なローディングUIを表示してもよいでしょう。
43-55
: スクリプト読み込みリトライ処理について
単純なカウンターによるリトライ方式でも目的は達成できます。ネットワーク状態の不安定が想定される場合や大規模運用を考慮する際は、待機時間を設定するエクスポネンシャルバックオフなどの導入も検討してみてください。
61-64
: マウント待ち時のレンダリング制御
マウント前にnull
を返すことでエラーを回避し、SSRとの競合を防いでいます。最終的にユーザー体験を向上させるために、簡易的なローディングUIを表示することも検討してください。
66-67
: デバッグログについて
本番環境向けには、console.log
の乱用が不要なログ混在を招く恐れがあるため、ログレベルの明確化やロガーの導入を検討するとよいでしょう。
68-85
: CubismCoreスクリプト読み込みの実装
リトライ処理を含めた例外対策がしっかり実装されています。すべての試行が失敗した際にユーザーへ分かりやすいエラーの案内や、再読み込みの手段を提示するとさらに使いやすくなるでしょう。
86-103
: live2dスクリプト読み込みの実装
CubismCore読み込みと同様のリトライロジックになっており、整合性があります。共通化できる部分は関数へ切り出して重複を減らすことを検討いただくとコードがさらに整理されます。
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
public/scripts/live2d.min.js
is excluded by!**/*.min.js
public/scripts/live2dcubismcore.min.js
is excluded by!**/*.min.js
📒 Files selected for processing (9)
.env.example
(1 hunks).eslintrc.json
(1 hunks).gitignore
(1 hunks)kyarasettei.txt
(1 hunks)src/components/live2DViewer.tsx
(1 hunks)src/components/speakers_aivis.json
(0 hunks)src/features/messages/live2dHandler.ts
(1 hunks)src/features/messages/speakQueue.ts
(3 hunks)src/features/stores/settings.ts
(4 hunks)
💤 Files with no reviewable changes (1)
- src/components/speakers_aivis.json
🚧 Files skipped from review as they are similar to previous changes (3)
- .eslintrc.json
- .gitignore
- src/features/messages/speakQueue.ts
🧰 Additional context used
🪛 Biome (1.9.4)
src/features/messages/live2dHandler.ts
[error] 86-86: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 98-98: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 125-125: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 144-144: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 151-151: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 157-157: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 161-161: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 161-162: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
🔇 Additional comments (9)
kyarasettei.txt (2)
1-12
: キャラクター設定が適切に定義されています!
基本的な属性が明確に定義され、必要な情報が漏れなく含まれています。
45-52
: 注意事項が適切に定義されています!
非倫理的な行為の防止やタイムゾーンの考慮など、重要な注意事項が明確に記載されています。
src/features/messages/live2dHandler.ts (1)
83-84
: 静的メソッド内での「this」の使用を修正
静的メソッド内でのthis
の使用は避け、クラス名を使用することを推奨します。
以下の修正を提案します:
- const audioBlob = await new Blob([this.audioBufferToWav(renderedBuffer)], {
+ const audioBlob = await new Blob([Live2DHandler.audioBufferToWav(renderedBuffer)], {
src/components/live2DViewer.tsx (6)
1-2
: 'use client'の宣言について
特に問題はありません。この行はNext.jsのクライアントコンポーネント向けに必要な宣言です。
3-7
: インポートとストア参照について
import構文やhomeStoreの参照方法に大きな問題は見受けられません。
30-37
: リトライ回数管理の初期化
scriptLoadRetries
と MAX_RETRIES
の定義は適切です。将来的にリトライ回数を動的に変更する可能性がある場合は、環境変数や設定ファイルで管理すると拡張性が高まります。
38-42
: homeStoreの利用について
isCubismCoreLoaded
や isLive2dLoaded
をグローバルストアで管理する実装は問題ありません。ステート管理が明確に行われており、可読性も高いです。
56-59
: コンポーネントのマウント処理
isMounted
を使ってクライアントサイド専用の処理を明確に切り分ける方針は適切です。
104-106
: Live2DComponent の条件付きレンダリング
スクリプトが全て読み込まれた後にコンポーネントを描画するフローは適切です。表示タイミングを明確化でき、エラーを減らす効果が期待できます。
// AudioContextの作成 | ||
const audioContext = new AudioContext() | ||
let decodedAudio: AudioBuffer | ||
|
||
if (isNeedDecode) { | ||
// 圧縮音声の場合 | ||
decodedAudio = await audioContext.decodeAudioData(audioBuffer) | ||
} else { | ||
// PCM16形式の場合 | ||
const pcmData = new Int16Array(audioBuffer) | ||
const floatData = new Float32Array(pcmData.length) | ||
for (let i = 0; i < pcmData.length; i++) { | ||
floatData[i] = | ||
pcmData[i] < 0 ? pcmData[i] / 32768.0 : pcmData[i] / 32767.0 | ||
} | ||
decodedAudio = audioContext.createBuffer(1, floatData.length, 24000) // sampleRateは必要に応じて調整 | ||
decodedAudio.getChannelData(0).set(floatData) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
音声処理ロジックのエラーハンドリング強化
デコード処理でエラーが発生する可能性があるため、適切なエラーハンドリングの追加を推奨します。
以下のような修正を提案します:
// AudioContextの作成
- const audioContext = new AudioContext()
+ let audioContext: AudioContext
+ try {
+ audioContext = new AudioContext()
+ } catch (error) {
+ console.error('AudioContext の作成に失敗しました:', error)
+ throw new Error('音声の初期化に失敗しました')
+ }
let decodedAudio: AudioBuffer
if (isNeedDecode) {
// 圧縮音声の場合
- decodedAudio = await audioContext.decodeAudioData(audioBuffer)
+ try {
+ decodedAudio = await audioContext.decodeAudioData(audioBuffer)
+ } catch (error) {
+ console.error('音声のデコードに失敗しました:', error)
+ throw new Error('音声の処理に失敗しました')
+ }
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
// AudioContextの作成 | |
const audioContext = new AudioContext() | |
let decodedAudio: AudioBuffer | |
if (isNeedDecode) { | |
// 圧縮音声の場合 | |
decodedAudio = await audioContext.decodeAudioData(audioBuffer) | |
} else { | |
// PCM16形式の場合 | |
const pcmData = new Int16Array(audioBuffer) | |
const floatData = new Float32Array(pcmData.length) | |
for (let i = 0; i < pcmData.length; i++) { | |
floatData[i] = | |
pcmData[i] < 0 ? pcmData[i] / 32768.0 : pcmData[i] / 32767.0 | |
} | |
decodedAudio = audioContext.createBuffer(1, floatData.length, 24000) // sampleRateは必要に応じて調整 | |
decodedAudio.getChannelData(0).set(floatData) | |
} | |
// AudioContextの作成 | |
let audioContext: AudioContext | |
try { | |
audioContext = new AudioContext() | |
} catch (error) { | |
console.error('AudioContext の作成に失敗しました:', error) | |
throw new Error('音声の初期化に失敗しました') | |
} | |
let decodedAudio: AudioBuffer | |
if (isNeedDecode) { | |
// 圧縮音声の場合 | |
try { | |
decodedAudio = await audioContext.decodeAudioData(audioBuffer) | |
} catch (error) { | |
console.error('音声のデコードに失敗しました:', error) | |
throw new Error('音声の処理に失敗しました') | |
} | |
} else { | |
// PCM16形式の場合 | |
const pcmData = new Int16Array(audioBuffer) | |
const floatData = new Float32Array(pcmData.length) | |
for (let i = 0; i < pcmData.length; i++) { | |
floatData[i] = | |
pcmData[i] < 0 ? pcmData[i] / 32768.0 : pcmData[i] / 32767.0 | |
} | |
decodedAudio = audioContext.createBuffer(1, floatData.length, 24000) // sampleRateは必要に応じて調整 | |
decodedAudio.getChannelData(0).set(floatData) | |
} |
// Settings | ||
modelType: | ||
(process.env.NEXT_PUBLIC_MODEL_TYPE as 'vrm' | 'live2d') || 'vrm', | ||
|
||
// Live2D settings | ||
neutralEmotions: | ||
process.env.NEXT_PUBLIC_NEUTRAL_EMOTIONS?.split(',') || [], | ||
happyEmotions: process.env.NEXT_PUBLIC_HAPPY_EMOTIONS?.split(',') || [], | ||
sadEmotions: process.env.NEXT_PUBLIC_SAD_EMOTIONS?.split(',') || [], | ||
angryEmotions: process.env.NEXT_PUBLIC_ANGRY_EMOTIONS?.split(',') || [], | ||
relaxedEmotions: | ||
process.env.NEXT_PUBLIC_RELAXED_EMOTIONS?.split(',') || [], | ||
idleMotionGroup: process.env.NEXT_PUBLIC_IDLE_MOTION_GROUP || '', | ||
neutralMotionGroup: process.env.NEXT_PUBLIC_NEUTRAL_MOTION_GROUP || '', | ||
happyMotionGroup: process.env.NEXT_PUBLIC_HAPPY_MOTION_GROUP || '', | ||
sadMotionGroup: process.env.NEXT_PUBLIC_SAD_MOTION_GROUP || '', | ||
angryMotionGroup: process.env.NEXT_PUBLIC_ANGRY_MOTION_GROUP || '', | ||
relaxedMotionGroup: process.env.NEXT_PUBLIC_RELAXED_MOTION_GROUP || '', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
🛠️ Refactor suggestion
Live2D設定の初期化処理に関する問題を確認しました
コードベースの分析結果から、以下の点が明らかになりました:
- 空文字列の環境変数(
.env.example
で確認)はsplit(',')
により[""]
となり、これが実際に使用される可能性があります。 - モーショングループの値は
based.tsx
でデフォルト値が定義されており、UI上で適切に管理されています。
修正提案:
// Live2D settings
neutralEmotions:
- process.env.NEXT_PUBLIC_NEUTRAL_EMOTIONS?.split(',') || [],
+ (process.env.NEXT_PUBLIC_NEUTRAL_EMOTIONS || '').split(',').filter(Boolean) || [],
// 他の感情配列も同様に
live2dHandler.ts
での使用状況を確認したところ、配列の長さに基づいてランダム選択を行っているため、空文字列の要素が含まれると予期しない動作を引き起こす可能性があります。- モーショングループについては、UI側で適切なデフォルト値が設定されており、検証関数は不要と判断しました。
🔗 Analysis chain
Live2D設定の初期化処理について
環境変数からの設定読み込みが適切に実装されていますが、以下の点に注意が必要です:
- 空文字列の配列への分割は予期しない結果を招く可能性があります
- モーショングループの値が検証されていません
// Live2D settings
neutralEmotions:
- process.env.NEXT_PUBLIC_NEUTRAL_EMOTIONS?.split(',') || [],
+ process.env.NEXT_PUBLIC_NEUTRAL_EMOTIONS?.split(',').filter(Boolean) || [],
// 他の感情配列も同様に
idleMotionGroup:
- process.env.NEXT_PUBLIC_IDLE_MOTION_GROUP || '',
+ validateMotionGroup(process.env.NEXT_PUBLIC_IDLE_MOTION_GROUP),
// 他のモーショングループも同様に
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# 環境変数の設定例を確認
grep -r "NEXT_PUBLIC_.*EMOTIONS\|NEXT_PUBLIC_.*MOTION_GROUP" .env* 2>/dev/null || echo "環境変数の設定例が見つかりません"
Length of output: 432
Script:
#!/bin/bash
# Live2D関連のコードの使用箇所を確認
rg "(?:neutral|happy|sad|angry|relaxed)(?:Emotions|MotionGroup)" -B 2 -A 2
Length of output: 13472
Script:
#!/bin/bash
# validateMotionGroupのような検証関数が存在するか確認
ast-grep --pattern 'function validateMotionGroup'
rg "validateMotionGroup"
Length of output: 76
Script:
#!/bin/bash
# Live2Dの実装部分を確認
fd "live2d" --type f --exec rg "motionGroup|emotions" {} -l
Length of output: 61
@coderabbitai pause |
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (9)
src/pages/api/get-live2d-list.ts (1)
37-42
: エラーハンドリングの際に詳細をロギングしていますが、運用環境では情報過多に注意。
現在は単にconsole.error
を呼び出していますが、サーバーログに表示してよい情報かどうかを必要に応じて精査することをおすすめします。src/components/settings/based.tsx (3)
64-153
: Live2DSettingsFormコンポーネントのステート初期化処理が適切にまとめられています。
useEffect
内での初回レンダリング時のデフォルト値設定ロジックは妥当ですが、大規模化した場合は初期化専用のカスタムフックやユーティリティ関数を分離する検討も行うとさらに見通しが良くなるでしょう。
289-309
: VRM と Live2D を切り替える UI 実装がシンプルでユーザーにわかりやすいです。
ただし、利用頻度やモデル切り替えコストを考慮し、切り替え時に必要な状態リセットなど学習コストの軽減策を検討してもよいでしょう。
352-370
: Live2Dモデルのセレクトボックスと設定フォームが連携しています。
APIで取得したデータをストアと連携させるフローは良好です。スケールアップ時にモデル数が増加する場合に向け、検索機能の導入やUI整理も視野に入れてください。src/components/Live2DComponent.tsx (5)
1-9
: コンソールログの削除を推奨
console.log
ステートメントは開発用であり、本番環境には不要です。以下の変更を適用することを推奨します:
-console.log('Live2DComponent module loaded')
10-19
: モデルのスケール値をconstantsとして定義することを推奨スケール値(0.3)やその他の定数値は、コンポーネントの上部で定数として定義することで、保守性が向上します。
以下のような実装を推奨します:
+const DEFAULT_SCALE = 0.3; +const MODEL_SCALE_LIMITS = { + MIN: 0.1, + MAX: 2.0 +}; const setModelPosition = ( app: Application, model: InstanceType<typeof Live2DModel> ) => { - const scale = 0.3 - model.scale.set(scale) + model.scale.set(DEFAULT_SCALE) model.x = app.renderer.width / 2 model.y = app.renderer.height / 2 }
138-148
: スケール変更のパフォーマンス最適化ホイールイベントの処理で、スケール変更時にデバウンスを実装することで、パフォーマンスを改善できます。
以下のような実装を推奨します:
import { debounce } from 'lodash'; // スケール変更をデバウンス const debouncedScaleChange = debounce((newScale: number) => { if (newScale >= MODEL_SCALE_LIMITS.MIN && newScale <= MODEL_SCALE_LIMITS.MAX) { model.scale.set(newScale); } }, 16); // 約60FPS const handleWheel = (event: WheelEvent) => { event.preventDefault(); const scaleChange = event.deltaY * -0.0002; const newScale = model.scale.x + scaleChange; debouncedScaleChange(newScale); };
165-183
: リサイズイベントの最適化ウィンドウリサイズイベントのパフォーマンスを改善するため、デバウンス処理の実装を推奨します。
以下のような実装を推奨します:
useEffect(() => { if (!app || !model) return; const debouncedResize = debounce(() => { if (!canvasContainerRef.current) return; app.renderer.resize( canvasContainerRef.current.clientWidth, canvasContainerRef.current.clientHeight ); setModelPosition(app, model); }, 250); window.addEventListener('resize', debouncedResize); return () => { window.removeEventListener('resize', debouncedResize); debouncedResize.cancel(); }; }, [app, model]);
185-194
: アクセシビリティの改善キャンバス要素にARIAラベルを追加し、アクセシビリティを向上させることを推奨します。
以下のような実装を推奨します:
<canvas ref={canvasContainerRef} className="w-full h-full" onContextMenu={(e) => e.preventDefault()} + aria-label="Live2Dキャラクター表示エリア" + role="img" />
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/components/Live2DComponent.tsx
(1 hunks)src/components/settings/based.tsx
(3 hunks)src/features/stores/settings.ts
(6 hunks)src/pages/api/get-live2d-list.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/features/stores/settings.ts
🔇 Additional comments (5)
src/pages/api/get-live2d-list.ts (2)
5-8
: エンドポイント作成における基本的なアプローチは問題ありません。
新規エンドポイントとしての設計がシンプルで読みやすく、メンテナンス性が高いです。
21-34
: フォルダごとのファイル探索ロジックが明確に整理されています。
for (const folder of folders)
の使用は可読性が高く、各フォルダからモデルファイルを抽出する流れもわかりやすいです。
src/components/settings/based.tsx (2)
11-37
: 感情(Emotion)のデフォルト値の管理ロジックが明確です。
それぞれの配列に初期値を設定することで、利用者にも意図が伝わりやすい構造となっています。
39-62
: モーション(Motion)用の定義を分割している点は可読性向上に寄与します。
emotionFields
と motionFields
を同じファイルで管理しており、後の拡張に備えた変数設計として良いアプローチです。
src/components/Live2DComponent.tsx (1)
1-196
: メモリリークの防止とパフォーマンスの検証
コンポーネントのアンマウント時のクリーンアップは実装されていますが、長時間の使用時やモデル切り替え時のメモリ使用状況を検証することを推奨します。
以下のスクリプトを実行して、メモリリークの可能性がある箇所を特定します:
✅ Verification successful
メモリ管理とイベントリスナーの実装は適切に行われています
コードの検証結果、以下の点から適切なメモリ管理が実装されていることを確認しました:
-
コンポーネントのアンマウント時に適切なクリーンアップが実装されています:
- Live2Dモデルの
destroy()
による解放 - PIXIアプリケーションの
destroy()
による解放 - モデル切り替え時の古いモデルの適切な破棄
- Live2Dモデルの
-
イベントリスナーの管理が適切に行われています:
- すべてのイベントリスナー(pointer、wheel、resize)に対して、useEffectのクリーンアップ関数で適切に削除処理が実装されています
- イベントリスナーの依存配列が適切に設定されています
-
useEffectの依存配列が適切に管理されており、不要な再レンダリングやメモリリークを防ぐ実装となっています
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Live2Dモデルのメモリ管理に関連するコードを検索
echo "Searching for potential memory leak points in Live2D implementation..."
# モデルのクリーンアップ処理の検索
rg "destroy|dispose|cleanup" --type ts
# イベントリスナーの追加/削除の検索
rg "addEventListener|removeEventListener" --type ts
# メモリ管理に関連する可能性のあるuseEffect依存配列の検索
ast-grep --pattern 'useEffect(() => {
$$$
}, [$_])'
Length of output: 13234
const loadLive2DModel = async ( | ||
currentApp: Application, | ||
modelPath: string | ||
) => { | ||
if (!canvasContainerRef.current) return | ||
const hs = homeStore.getState() | ||
|
||
try { | ||
const newModel = await Live2DModel.fromSync(modelPath, { | ||
ticker: Ticker.shared, | ||
autoHitTest: false, | ||
autoFocus: false, | ||
}) | ||
|
||
await new Promise((resolve, reject) => { | ||
newModel.once('load', () => resolve(true)) | ||
newModel.once('error', (e) => reject(e)) | ||
setTimeout(() => reject(new Error('Model load timeout')), 10000) | ||
}) | ||
|
||
currentApp.stage.addChild(newModel as unknown as DisplayObject) | ||
newModel.anchor.set(0.5, 0.5) | ||
setModelPosition(currentApp, newModel) | ||
|
||
modelRef.current = newModel | ||
setModel(newModel) | ||
hs.live2dViewer = newModel | ||
|
||
await Live2DHandler.resetToIdle() | ||
} catch (error) { | ||
console.error('Failed to load Live2D model:', error) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
エラーハンドリングの改善が必要
モデルのロード失敗時のエラーハンドリングが不十分です。ユーザーへのフィードバックやフォールバック処理を追加することを推奨します。
以下のような実装を推奨します:
} catch (error) {
console.error('Failed to load Live2D model:', error)
+ // ユーザーへのエラー通知
+ homeStore.getState().setError({
+ type: 'live2d',
+ message: 'Live2Dモデルの読み込みに失敗しました'
+ });
+ // フォールバック処理
+ if (modelRef.current) {
+ currentApp.stage.removeChild(modelRef.current as unknown as DisplayObject);
+ modelRef.current.destroy();
+ modelRef.current = null;
+ setModel(null);
+ }
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const loadLive2DModel = async ( | |
currentApp: Application, | |
modelPath: string | |
) => { | |
if (!canvasContainerRef.current) return | |
const hs = homeStore.getState() | |
try { | |
const newModel = await Live2DModel.fromSync(modelPath, { | |
ticker: Ticker.shared, | |
autoHitTest: false, | |
autoFocus: false, | |
}) | |
await new Promise((resolve, reject) => { | |
newModel.once('load', () => resolve(true)) | |
newModel.once('error', (e) => reject(e)) | |
setTimeout(() => reject(new Error('Model load timeout')), 10000) | |
}) | |
currentApp.stage.addChild(newModel as unknown as DisplayObject) | |
newModel.anchor.set(0.5, 0.5) | |
setModelPosition(currentApp, newModel) | |
modelRef.current = newModel | |
setModel(newModel) | |
hs.live2dViewer = newModel | |
await Live2DHandler.resetToIdle() | |
} catch (error) { | |
console.error('Failed to load Live2D model:', error) | |
} | |
} | |
const loadLive2DModel = async ( | |
currentApp: Application, | |
modelPath: string | |
) => { | |
if (!canvasContainerRef.current) return | |
const hs = homeStore.getState() | |
try { | |
const newModel = await Live2DModel.fromSync(modelPath, { | |
ticker: Ticker.shared, | |
autoHitTest: false, | |
autoFocus: false, | |
}) | |
await new Promise((resolve, reject) => { | |
newModel.once('load', () => resolve(true)) | |
newModel.once('error', (e) => reject(e)) | |
setTimeout(() => reject(new Error('Model load timeout')), 10000) | |
}) | |
currentApp.stage.addChild(newModel as unknown as DisplayObject) | |
newModel.anchor.set(0.5, 0.5) | |
setModelPosition(currentApp, newModel) | |
modelRef.current = newModel | |
setModel(newModel) | |
hs.live2dViewer = newModel | |
await Live2DHandler.resetToIdle() | |
} catch (error) { | |
console.error('Failed to load Live2D model:', error) | |
// ユーザーへのエラー通知 | |
homeStore.getState().setError({ | |
type: 'live2d', | |
message: 'Live2Dモデルの読み込みに失敗しました' | |
}); | |
// フォールバック処理 | |
if (modelRef.current) { | |
currentApp.stage.removeChild(modelRef.current as unknown as DisplayObject); | |
modelRef.current.destroy(); | |
modelRef.current = null; | |
setModel(null); | |
} | |
} | |
} |
✅ Actions performedReviews paused. |
@coderabbitai resume |
✅ Actions performedReviews resumed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (52)
public/live2d/nike01/motions/Motion6.motion3.json (3)
38-64
: 目のアニメーションの改善提案目のパラメータ(ParamEyeLOpen、ParamEyeROpen)について:
- 現在の瞬きの動きが機械的に見える可能性があります
- 値が0から1.2まで急激に変化しています
以下のような調整を推奨します:
- 1.2, 1, 0.989, 1.2, 1.011, 0, 1.033, 0, 1, 1.067, 0, 1.1, 1.2, 1.133, + 1.2, 1, 0.989, 1.2, 1.011, 0.2, 1.033, 0, 1, 1.067, 0.2, 1.1, 1.2, 1.133,
105-120
: 口の表情変化の自然さについて口の形状(ParamMouthForm)と開き具合(ParamMouthOpenY)のパラメータについて:
- 値の変化が急激すぎる箇所があります(-2への急な変化)
- より自然な表情変化のために、中間値の追加を検討してください
129-137
: 体の動きの調整提案体の角度(ParamBodyAngleY)について:
- 10から-6への急激な変化が不自然に見える可能性があります
- より滑らかな動きのために、中間フレームの追加を推奨します
以下のような調整を提案します:
- 1, 0.667, 10, 0.733, -6, 0.8, -6, 1, 0.833, -6, 0.867, 5, 0.9, 5, 1, + 1, 0.667, 10, 0.7, 2, 0.733, -6, 0.8, -6, 1, 0.833, -6, 0.867, 5, 0.9, 5, 1,public/live2d/nike01/motions/Motion3.motion3.json (3)
14-82
: 顔の表情パラメータの最適化を推奨目と頬のパラメータにおいて、以下の改善点が見られます:
- 目の開閉(ParamEyeLOpen/ParamEyeROpen)の同期が完全ではありません
- 笑顔パラメータ(ParamEyeLSmile/ParamEyeRSmile)が使用されていません
目のパラメータを同期させ、表情をより自然にするために以下の修正を提案します:
- "Segments": [ - 0, 1, 1, 0.056, 1, 0.111, 1, 0.167, 1, 1, 0.2, 1, 0.233, 1, 0.267, 1, 1, - 0.322, 1, 0.378, 0, 0.433, 0, 1, 0.478, 0, 0.522, 0, 0.567, 0, 1, 0.644, - 0, 0.722, 1, 0.8, 1, 1, 1.056, 1, 1.311, 0.988, 1.567, 0.988, 1, 1.789, - 0.988, 2.011, 1, 2.233, 1, 1, 2.267, 1, 2.3, 1, 2.333, 1, 1, 2.367, 1, - 2.4, 0, 2.433, 0, 1, 2.478, 0, 2.522, 0, 2.567, 0, 1, 2.622, 0, 2.678, - 1, 2.733, 1, 0, 4.2, 1 - ] + "Segments": [ + 0, 1, 1, 0.056, 1, 0.111, 1, 0.167, 1, 1, 0.2, 1, 0.233, 1, 0.267, 1, 1, + 0.322, 1, 0.378, 0, 0.433, 0, 1, 0.478, 0, 0.522, 0, 0.567, 0, 1, 0.644, + 0, 0.722, 1, 0.8, 1, 1, 1.056, 1, 1.311, 1, 1.567, 1, 1, 1.789, 1, + 2.011, 1, 2.233, 1, 1, 2.267, 1, 2.3, 1, 2.333, 1, 1, 2.367, 1, + 2.4, 0, 2.433, 0, 1, 2.478, 0, 2.522, 0, 2.567, 0, 1, 2.622, 0, 2.678, + 1, 2.733, 1, 0, 4.2, 1 + ]
161-169
: 腕の動きの同期を改善ParamArmLAとParamArmRAのモーションにおいて:
- 左右の腕の動きの同期が取れていない箇所があります
- 初期値が両方-10から始まっていますが、自然な立ち位置としては適切でない可能性があります
より自然な動きにするために、両腕の動きを同期させることを推奨します。
Also applies to: 172-180
183-193
: アホ毛のモーションが過剰ParamHairAhogeのモーションにおいて:
- 値の変化が大きすぎる(-10から10までの振れ幅)
- 動きが急激すぎる箇所があります
より自然な動きにするために、振れ幅を抑えることを推奨します:
"Segments": [ 0, 0, 1, 0.122, 0, 0.244, -3.127, 0.367, -4, 1, 0.511, -5.032, 0.656, - -5, 0.8, -5, 1, 0.9, -5, 1, 10, 1.1, 10, 1, 1.267, 10, 1.433, 10.072, + -5, 0.8, -5, 1, 0.9, -5, 1, 7, 1.1, 7, 1, 1.267, 7, 1.433, 7.072, 1.6, 8, 1, 1.722, 6.481, 1.844, -10, 1.967, -10, 1, 2.122, -10, 2.278, - -10.146, 2.433, -9.434, 1, 2.589, -8.722, 2.744, 10, 2.9, 10, 1, 3.011, + -7.146, 2.433, -6.434, 1, 2.589, -5.722, 2.744, 7, 2.9, 7, 1, 3.011, 10, 3.122, -5.646, 3.233, -5.646, 1, 3.367, -5.646, 3.5, 3.825, 3.633, 3.825, 1, 3.767, 3.825, 3.9, 0, 4.033, 0, 0, 4.2, 0 ]src/features/messages/speakQueue.ts (3)
27-27
:settingsStore
呼び出し時の変数名に一貫性を検討
hs
とss
のように異なる名前を使っており、可読性を保つために命名規則を統一することをおすすめします。
33-37
: モデル種別の分岐は適切だが拡張性に注意
modelType
が増える将来に備え、定数化や列挙型の導入で可読性と保守性を高めることを検討してください。
63-68
: 同様の条件分岐が散在している点に留意
resetToIdle
とplayEmotion('neutral')
の切り替えは分かりやすい実装ですが、同様の分岐が増える場合は抽象化や共通化も検討するとメンテナンスが容易になります。src/features/messages/live2dHandler.ts (2)
8-111
:speak
メソッドの責務が大きいので注意
オーディオのデコード、Blob生成、Live2Dモーションや表情設定のロジックを一括で担っています。可読性を高めるため、小分けのヘルパーメソッド導入を検討してください。また、静的メソッド内でのthis
呼び出しはクラス名を使った方が明確になります。🧰 Tools
🪛 Biome (1.9.4)
[error] 86-86: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.(lint/complexity/noThisInStatic)
[error] 98-98: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.(lint/complexity/noThisInStatic)
149-202
:audioBufferToWav
は有用だが切り出しも検討
WAVヘッダー作成からバッファ列挙までの処理は他でも使われる可能性があるため、専用ユーティリティとして切り出して再利用することをおすすめします。また、静的コンテキストでのthis
使用については前述の指摘と同様です。🧰 Tools
🪛 Biome (1.9.4)
[error] 151-151: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.(lint/complexity/noThisInStatic)
[error] 157-157: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.(lint/complexity/noThisInStatic)
[error] 161-161: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.(lint/complexity/noThisInStatic)
[error] 161-162: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.(lint/complexity/noThisInStatic)
src/components/settings/based.tsx (4)
39-63
: モーション設定フィールドの配列定義
motionFields
も同様に配列で管理しており一貫性があります。感情フィールドと合わせて命名をより厳密にすると分かりやすさが増すでしょう。
158-163
:selectedLive2DPath
とmodelType
の追加
VRM と Live2D を選択的に扱うための状態管理は妥当です。複数モデルを扱う場合、もう少し階層化するなどの検討も可能です。
289-309
: VRM/Live2D トグルボタンの実装
UX向上のために分かりやすいスタイルの切り替えが行われています。タップやクリック時の切り替え効果をさらに明示すると、ユーザーにとってわかりやすいUIとなるでしょう。
312-370
: VRM と Live2D のコンディショナルレンダリング
modelType
に応じたコンポーネントの切り替えが明確です。さらに共通化できる部分がある場合、一部ロジックを関数でまとめると見通しが良くなる可能性があります。src/pages/api/get-live2d-list.ts (1)
5-43
: ディレクトリ走査とレスポンス処理
public/live2d
下のフォルダを走査し、.model3.json
を検知して配列化するロジックは簡潔です。大量のモデルを扱う場合を想定し、非同期処理での例外制御を強化することも検討してください。src/features/stores/home.ts (1)
29-32
: 新しいフラグ類 (isCubismCoreLoaded
,isLive2dLoaded
)
Live2D初期化処理を追跡するためのフラグをストアで管理するのは適切です。複数のLive2Dモデルやロードステータスを拡張する場合には、さらなるステート分割も考えられます。src/components/live2DViewer.tsx (3)
38-41
: homeStore の依存管理に注意してください。
複数のステートを homeStore から取得していますが、参照するステートやアクションが増えた場合には、読み込みコストやレンダリングの再実行頻度が増える可能性があります。必要に応じてコンポーネントを分割し、ステート更新の影響範囲を局所化することを検討してください。
56-59
: コンポーネントのライフサイクルログは開発には有用ですが、本番では必要に応じて取り除くことを検討してください。
console.log('Live2DViewer mounted')
などのログはデバッグ用途と認識します。本番環境での不要なログはパフォーマンスやセキュリティの観点から抑制することをご検討ください。
68-105
: スクリプト読み込みのリトライ機能が適切に実装されています。
最大リトライ回数MAX_RETRIES
が設定され、読み込み失敗時にretryLoadScript
で制御している点は堅牢です。将来的にスクリプト数が増えた場合、同様のパターンを繰り返し実装する可能性があるため、共通ロジックとしてモジュール化することを検討してください。src/features/messages/speakCharacter.ts (2)
242-248
: VRM と Live2D を切り替える条件分岐は明快です。
if (ss.modelType === 'vrm') ... else if (ss.modelType === 'live2d') ...
のような分岐が増える場合、列挙型やマップによるディスパッチ手法を導入して保守性を高めることを検討してください。
267-273
: 音声再生処理の分岐も同様に整理が可能です。
今後、他のモデルタイプが追加された場合に備え、共通処理と各モデル固有処理を分離する形にすると、拡張時にコードが煩雑になりにくくなります。public/live2d/nike01/expressions/HairpinChange.exp3.json (1)
1-10
: HairpinChange.exp3.json のパラメータ設定の意図を明示すると保守性が上がります。
Add モードで 1 を指定しているようですが、他のエクスプレッションファイルに対する相対的な役割をコメントなどで追記すると、今後のモデルチューニング時の混乱を避けられます。public/live2d/nike01/expressions/NoSmile.exp3.json (1)
3-3
: ドキュメント追加の推奨表情パラメータの意図や使用方法を説明するドキュメントの追加を推奨します。特に:
- 各パラメータの有効な値の範囲
- パラメータの組み合わせによる効果
- 想定される使用シーン
ドキュメントのテンプレートを生成しますか?
public/live2d/nike01/expressions/Happy.exp3.json (1)
4-24
: パラメータ値の調整を推奨すべてのパラメータ値が1に設定されており、表情が極端になる可能性があります。より自然な表情を実現するために、以下の調整を検討してください:
- 目のスマイル(
ParamEyeRSmile
、ParamEyeLSmile
):0.7-0.8程度- 口の形(
ParamMouthForm
):0.8程度これにより、より自然で柔らかい「幸せ」の表情を表現できます。
public/live2d/nike01/expressions/Angry.exp3.json (2)
1-26
: パラメータ設定が適切です怒りの表情に対するパラメータ設定が適切に調整されています:
- 眉の怒り(
ParamAngerBrows
)が0.5で自然な表情を実現- 口の開き(
ParamMouthOpenY
)が0で引き締まった表情を表現- その他のパラメータも表情に合わせて適切に設定
表情パラメータの意図や調整方法についてのドキュメントを追加することを推奨します。新しい表情を追加する際の参考になります。
1-26
: 表情設定ファイル間の一貫性についてHappy.exp3.jsonとAngry.exp3.jsonの間で、以下の点で良好な一貫性が保たれています:
- ファイル構造が統一されている
- フェードイン時間が0.75秒で統一
- パラメータ命名規則が統一
今後、新しい表情を追加する際も、この一貫性を維持することを推奨します。
表情パラメータの命名規則や設定値の範囲についてのスタイルガイドの作成を検討してください。
public/live2d/nike01/expressions/Sad.exp3.json (1)
1-26
: 表情パラメータの詳細なドキュメント化を推奨します以下の点について改善を提案します:
ParamMouthOpenY
の0.224という具体的な値の根拠- 各パラメータの組み合わせによる表情の説明
- 他の悲しい表情との違いの文書化
JSONスキーマを作成して、パラメータの有効範囲とドキュメントを定義することを推奨します。
public/live2d/nike01/expressions/Troubled.exp3.json (1)
1-26
: Live2D表情設定ファイルの全体的な改善提案表情設定ファイル全体について、以下の改善を提案します:
- 表情パラメータの標準化とドキュメント化
- JSONスキーマによるバリデーション
- 表情テスト用のプレビューツールの導入
- パラメータ値の精度の統一基準の策定
#!/bin/bash # 表情設定ファイルの構造を確認 fd -e json -x jq -r 'keys' {} \; public/live2d/nike01/expressions/表情設定の管理と品質保証のための包括的なワークフローの確立を推奨します。
.gitignore (1)
51-52
: Live2Dモデルの管理方針の明確化が必要です現在の設定では、
nike01
以外のすべてのLive2Dモデルが無視されます。これは以下の潜在的な問題を引き起こす可能性があります:
- 新しいモデルを追加する際に、明示的な除外を忘れる可能性
- どのモデルがバージョン管理されているか把握しづらい
以下のような構造に変更することを推奨します:
-public/live2d/* -!public/live2d/nike01 +# Live2D models +public/live2d/* +# Tracked models (add new models here) +!public/live2d/nike01 +# Ignore generated files in tracked models +public/live2d/*/generated/*また、
README.md
にLive2Dモデルの管理方針を記載することを推奨します。public/live2d/nike01/expressions/Think2.exp3.json (1)
4-29
: パラメータの命名規則について提案パラメータIDの命名規則について、以下の標準化を推奨します:
- 目の動きに関連するパラメータ(EyeBall系)をグループ化
- 口の形状に関連するパラメータ(Mouth系)をグループ化
これにより、将来の表情追加や調整が容易になります。public/live2d/nike01/motions/Motion9.motion3.json (1)
18-22
: セグメント値の可読性向上を提案現在のセグメント値は1行に長く記述されており、可読性が低くなっています。以下のような配列形式での記述を推奨します:
- 0, 0, 1, 0.111, 0, 0.222, -15, 0.333, -15, 1, 0.444, -15, 0.556, 15, - 0.667, 15, 1, 0.778, 15, 0.889, -15, 1, -15, 1, 1.111, -15, 1.222, 15, - 1.333, 15, 1, 1.433, 15, 1.533, 2.85, 1.633, 0.42 + [ + [0, 0, 1], + [0.111, 0, 0.222], + [-15, 0.333, -15], + // ... 残りのセグメント + ]これにより:
- 各セグメントの値が明確になります
- モーションの調整が容易になります
- デバッグが簡単になります
public/live2d/nike01/expressions/Focus.exp3.json (1)
1-51
: パラメータの整理と値の最適化を推奨します表情設定は適切ですが、以下の改善を提案させていただきます:
- パラメータのグループ化
- 目に関する設定(ParamEyeLOpen, ParamEyeROpen, ParamEyeBallY)
- 眉に関する設定(ParamAngerBrows, ParamTroubleBrows)
- 口に関する設定(ParamMouthOpenY, ParamMouthForm)
- その他の設定(ParamBodyAngleY, ParamHairpinChange)
- 数値の最適化
- 小数点以下3桁までの精度で十分かと思われます
- より直感的な数値(例:-0.377→-0.38)の使用を検討
{ "Type": "Live2D Expression", "FadeInTime": 0.75, "Parameters": [ + // 目のパラメータ { "Id": "ParamEyeLOpen", - "Value": -0.377, + "Value": -0.38, "Blend": "Add" }, // ... 残りのパラメータも同様に整理 ] }public/live2d/nike01/expressions/Think.exp3.json (1)
1-61
: 自然な「考え中」の表情が実現されています表情設定は非常に良く考えられていますが、さらなる改善点を提案させていただきます:
- 表情の自然さ
- 頭の傾き(ParamAngleZ: 20.192)と視線の動き(ParamEyeBallX/Y)が自然に連動
- 左右の目の開き方の違い(ParamEyeLOpen: -0.158, ParamEyeROpen: -0.031)が自然な表情を演出
- 最適化提案
ParamEyeLSmile
とParamEyeRSmile
が0の場合は省略可能ParamTroubleBrows
が0の場合は省略可能- 数値の丸め処理を推奨(例:20.192→20.2)
パラメータの整理例:
{ "Parameters": [ { "Id": "ParamAngleZ", - "Value": 20.192, + "Value": 20.2, "Blend": "Add" }, - { - "Id": "ParamEyeLSmile", - "Value": 0, - "Blend": "Add" - }, // ... 残りのパラメータ ] }src/pages/index.tsx (1)
20-20
: モデルタイプの条件分岐について、エラーハンドリングの追加を推奨無効なモデルタイプが指定された場合のフォールバック処理が実装されていません。
以下のような実装を検討してください:
- {modelType === 'vrm' ? <VrmViewer /> : <Live2DViewer />} + {modelType === 'vrm' ? ( + <VrmViewer /> + ) : modelType === 'live2d' ? ( + <Live2DViewer /> + ) : ( + <div className="text-red-500">無効なモデルタイプです: {modelType}</div> + )}Also applies to: 26-26
kyarasettei.txt (1)
17-18
: 応答の長さと感情表現の一貫性について2文以内での返答という制約と5種類の感情表現は適切ですが、感情の遷移ルールが定義されていません。急激な感情の変化を防ぐため、感情の遷移ルールの追加を検討してください。
public/live2d/nike01/nike01.model3.json (2)
67-121
: モーショングループの重複を最適化複数の感情状態で同じモーションファイル(例:Motion1.motion3.json)が使用されています。これは以下の問題を引き起こす可能性があります:
- メモリ使用量の増加
- 感情の区別が不明確
モーションファイルを感情ごとに分離することを推奨します:
"Motions": { "Neutral": [ { - "File": "motions/Motion1.motion3.json" + "File": "motions/Neutral_1.motion3.json" } ], "Happy": [ { - "File": "motions/Motion1.motion3.json" + "File": "motions/Happy_1.motion3.json" } ] }
123-134
: パラメータグループの拡張を検討現在のパラメータグループは基本的な表情制御(LipSync、EyeBlink)のみをカバーしています。より豊かな表現のために、以下のパラメータの追加を検討してください:
- 頭の動き
- 体の動き
- 呼吸のモーション
.env.example (2)
155-156
: モデルタイプの選択肢を明確化
NEXT_PUBLIC_MODEL_TYPE
の有効な選択肢を明示的にコメントで示すべきです。# Model Type (vrm or live2d) -NEXT_PUBLIC_MODEL_TYPE="" +# 有効な値: "vrm" | "live2d" +NEXT_PUBLIC_MODEL_TYPE="vrm"
159-164
: 感情設定の形式を明確化感情設定の入力形式とデフォルト値を明示的に示すべきです。
# Emotions (comma separated) -NEXT_PUBLIC_NEUTRAL_EMOTIONS="" -NEXT_PUBLIC_HAPPY_EMOTIONS="" -NEXT_PUBLIC_SAD_EMOTIONS="" -NEXT_PUBLIC_ANGRY_EMOTIONS="" -NEXT_PUBLIC_RELAXED_EMOTIONS="" +# 形式: "emotion1,emotion2,emotion3" +NEXT_PUBLIC_NEUTRAL_EMOTIONS="Neutral,NoSmile" +NEXT_PUBLIC_HAPPY_EMOTIONS="Happy,Happy2" +NEXT_PUBLIC_SAD_EMOTIONS="Sad,Sad2,Troubled" +NEXT_PUBLIC_ANGRY_EMOTIONS="Angry" +NEXT_PUBLIC_RELAXED_EMOTIONS="Sleep,Think"src/components/Live2DComponent.tsx (1)
138-148
: スケール変更の最適化ホイールイベントのパフォーマンスを最適化し、スケール変更をより滑らかにする必要があります。
const handleWheel = (event: WheelEvent) => { event.preventDefault() - const scaleChange = event.deltaY * -0.0002 + // RAF(requestAnimationFrame)を使用してスケール変更を最適化 + const scaleChange = event.deltaY * -0.0001 + requestAnimationFrame(() => { const newScale = model.scale.x + scaleChange if (newScale >= 0.1 && newScale <= 2.0) { model.scale.set(newScale) } + }) }public/live2d/nike01/motions/Motion4.motion3.json (1)
51-57
: 目の動きの同期が最適化されています左右の目の動きが適切に同期されており、自然な表情を実現しています。ただし、以下の微調整を検討してください:
- まばたきの速度をわずかに調整
- 開閉の中間状態をより滑らかに
Also applies to: 68-72
public/live2d/nike01/motions/Motion7.motion3.json (1)
126-129
: 口の動きのパフォーマンス最適化
ParamMouthOpenY
のセグメントが細かく分割されすぎています。パフォーマンスを考慮して、以下の最適化を推奨します:
- セグメント数を減らす
- キーフレーム間の補間を活用
public/live2d/nike01/motions/Motion1.motion3.json (1)
19-23
: ParamAngleXのモーション遷移が急激ですX軸の角度変化において、値の遷移が急激な箇所が見られます。特に2.033から3.067の間で0度から9度への急な変化があります。
以下のように、より滑らかな遷移を実現することを推奨します:
- -8, 1, 1.522, -8, 1.778, 0, 2.033, 0, 1, 2.122, 0, 2.211, 0, 2.3, 0, 1, - 2.556, 0, 2.811, 9, 3.067, 9, 1, 3.356, 9, 3.644, 0, 3.933, 0, 1, 4.067, + -8, 1, 1.522, -8, 1.778, -4, 2.033, 0, 1, 2.122, 0, 2.211, 0, 2.3, 0, 1, + 2.556, 3, 2.811, 6, 3.067, 9, 1, 3.356, 9, 3.644, 4, 3.933, 0, 1, 4.067,public/live2d/nike01/motions/Motion2.motion3.json (1)
69-72
: 感情表現のパラメータグループ化を推奨
ParamEyeLSmile
とParamEyeRSmile
など、関連するパラメータが分散して定義されています。メンテナンス性と再利用性を向上させるため、以下の改善を提案します:
- 感情表現に関連するパラメータをグループ化
- 共通のタイミング値を変数として定義
- 感情の強度を一元管理できる仕組みの導入
Also applies to: 90-93
locales/zh/translation.json (1)
207-224
: Live2D関連の翻訳キーの体系化を推奨Live2D関連の翻訳キーが追加されていますが、より体系的な構造にすることで保守性が向上します。
以下のような構造化を提案します:
"Live2D": { - "Info": "可以指定表情和动作。\n每个表情都由提示控制。详情请参阅"AI设置 => 角色设置"。", + "settings": { + "info": "可以指定表情和动作。\n每个表情都由提示控制。详情请参阅"AI设置 => 角色设置"。", + }, - "Emotions": "表情设置", - "EmotionInfo": "感情可以以逗号分隔的方式指定。如果指定多个表情,将随机选择。", + "emotions": { + "title": "表情设置", + "info": "感情可以以逗号分隔的方式指定。如果指定多个表情,将随机选择。", + "types": { + "neutral": "通常", + "happy": "高兴", + "sad": "悲伤", + "angry": "愤怒", + "relaxed": "放松" + } + }public/live2d/nike01/motions/Motion5.motion3.json (1)
48-76
: 表情パラメータの設定についてParamCheekの値が常に0で変化がありません。表情の豊かさを向上させるため、感情表現時にはチークの値も変更することを推奨します。
- "Segments": [ - 0, 0, 1, 0.2, 0, 0.4, 0, 0.6, 0, 1, 2.844, 0, 5.089, 0, 7.333, 0, 0, - 8.567, 0 - ] + "Segments": [ + 0, 0, 1, 0.2, 0, 0.4, 0.3, 0.6, 0.3, 1, 2.844, 0.3, 5.089, 0.3, 7.333, 0, 0, + 8.567, 0 + ]public/live2d/nike01/nike01.cdi3.json (1)
1-598
: Live2Dモデルのパラメータ設定に関する提案このファイルは適切に構造化されていますが、以下の点について改善を提案します:
- パラメータの値の範囲や単位などのメタデータが不足しています
- パラメータ間の依存関係が明示されていません
JSONスキーマを追加して、パラメータの制約を定義することを推奨します:
{ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "Parameters": { "type": "array", "items": { "type": "object", "properties": { "Id": { "type": "string" }, "GroupId": { "type": "string" }, "Name": { "type": "string" }, "Min": { "type": "number" }, "Max": { "type": "number" }, "Unit": { "type": "string" } } } } } }locales/en/translation.json (1)
207-224
: Live2D関連の翻訳キーの構造化について感情とモーションの設定に関する翻訳が追加されていますが、以下の点について改善を提案します:
- 感情とモーションの説明がより詳細であるべきです
- 各感情の使用例が不足しています
以下のような構造に改善することを推奨します:
"Live2D": { "EmotionInfo": "Emotions can be specified in comma-separated format. If multiple emotions are specified, they are randomly selected.\nThe initial value is for the model provided by AITuberKit. If you are using an original model, please enter the value according to your model.\nAfter conversation completion, the \"Neutral\" emotion is displayed.", - "neutralEmotions": "Neutral", + "neutralEmotions": "Neutral - 通常の表情(例:[neutral]こんにちは)", - "happyEmotions": "Happy", + "happyEmotions": "Happy - 嬉しい表情(例:[happy]やったー!)", // 他の感情も同様に }src/components/settings/modelProvider.tsx (1)
963-968
: 条件付きレンダリングの実装がクリーンです!キャラクター設定プロンプトの表示ロジックが適切に実装されており、Difyサービスと他のサービスで異なる説明文を表示する処理が明確です。また、
whitespace-pre-line
クラスの使用により、一般的な説明文の改行が適切に保持されています。可読性をさらに向上させるため、以下のような実装も検討してください:
- {selectAIService === 'dify' ? ( - <div className="my-16">{t('DifyInstruction')}</div> - ) : ( - <div className="my-16 whitespace-pre-line"> - {t('CharacterSettingsInfo')} - </div> - )} + <div className={`my-16 ${selectAIService !== 'dify' ? 'whitespace-pre-line' : ''}`}> + {selectAIService === 'dify' ? t('DifyInstruction') : t('CharacterSettingsInfo')} + </div>public/live2d/nike01/motions/Motion8.motion3.json (2)
45-67
: 目のアニメーションの遷移をより滑らかにすることを推奨現在の目の開閉アニメーション(ParamEyeLOpen/ParamEyeROpen)にはやや急激な遷移が見られます。より自然な表現のために、以下の調整を検討してください:
- 開閉の中間値(0.8から0への遷移)をより細かく設定
- まばたきの速度調整
183-186
: パーツの不透明度のアニメーション化を検討現在のPartOpacityの設定は静的な値(1)のみとなっています。アニメーションの表現力を高めるために、以下の改善を提案します:
- 腕の動きに合わせた不透明度の変化
- フェードイン/アウト効果の追加
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (5)
package-lock.json
is excluded by!**/package-lock.json
public/live2d/nike01/nike01.8192/texture_00.png
is excluded by!**/*.png
public/scripts/live2d.min.js
is excluded by!**/*.min.js
public/scripts/live2dcubismcore.min.js
is excluded by!**/*.min.js
public/voice_test.wav
is excluded by!**/*.wav
📒 Files selected for processing (48)
.env.example
(1 hunks).eslintrc.json
(1 hunks).gitignore
(1 hunks).vscode/settings.json
(1 hunks)kyarasettei.txt
(1 hunks)locales/en/translation.json
(2 hunks)locales/ja/translation.json
(2 hunks)locales/ko/translation.json
(2 hunks)locales/zh/translation.json
(2 hunks)package.json
(1 hunks)public/live2d/nike01/expressions/Angry.exp3.json
(1 hunks)public/live2d/nike01/expressions/Focus.exp3.json
(1 hunks)public/live2d/nike01/expressions/HairpinChange.exp3.json
(1 hunks)public/live2d/nike01/expressions/Happy.exp3.json
(1 hunks)public/live2d/nike01/expressions/Happy2.exp3.json
(1 hunks)public/live2d/nike01/expressions/Neutral.exp3.json
(1 hunks)public/live2d/nike01/expressions/NoSmile.exp3.json
(1 hunks)public/live2d/nike01/expressions/Sad.exp3.json
(1 hunks)public/live2d/nike01/expressions/Sad2.exp3.json
(1 hunks)public/live2d/nike01/expressions/Sleep.exp3.json
(1 hunks)public/live2d/nike01/expressions/Think.exp3.json
(1 hunks)public/live2d/nike01/expressions/Think2.exp3.json
(1 hunks)public/live2d/nike01/expressions/Troubled.exp3.json
(1 hunks)public/live2d/nike01/expressions/Zitome.exp3.json
(1 hunks)public/live2d/nike01/items_pinned_to_model.json
(1 hunks)public/live2d/nike01/motions/Motion1.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion2.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion3.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion4.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion5.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion6.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion7.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion8.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion9.motion3.json
(1 hunks)public/live2d/nike01/nike01.cdi3.json
(1 hunks)public/live2d/nike01/nike01.model3.json
(1 hunks)public/locales/ja/translation.json
(1 hunks)src/components/Live2DComponent.tsx
(1 hunks)src/components/live2DViewer.tsx
(1 hunks)src/components/settings/based.tsx
(3 hunks)src/components/settings/modelProvider.tsx
(1 hunks)src/features/messages/live2dHandler.ts
(1 hunks)src/features/messages/speakCharacter.ts
(3 hunks)src/features/messages/speakQueue.ts
(3 hunks)src/features/stores/home.ts
(5 hunks)src/features/stores/settings.ts
(6 hunks)src/pages/api/get-live2d-list.ts
(1 hunks)src/pages/index.tsx
(2 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
src/features/messages/live2dHandler.ts
[error] 86-86: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 98-98: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 125-125: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 144-144: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 151-151: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 157-157: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 161-161: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 161-162: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
🔇 Additional comments (44)
public/live2d/nike01/motions/Motion6.motion3.json (2)
1-13
: メタデータの設定が適切です
アニメーションの基本設定が適切に構成されています:
- 1.9秒の長さは短いリアクションモーションとして適切です
- 30FPSは一般的なWeb表示に最適な設定です
- ループしない設定は一回限りの表情変化やリアクションとして適切です
167-176
: アホ毛のアニメーションについて
アホ毛のパラメータ(ParamHairAhoge)について:
- 自然な揺れのアニメーションが実装されています
- 物理的な動きとして適切です
public/live2d/nike01/motions/Motion3.motion3.json (1)
1-13
: メタ設定の検証が必要です
アニメーション設定において以下の点を確認してください:
- 4.2秒の継続時間は適切ですが、ループしないモーションとしては長めかもしれません
- 30FPSは標準的ですが、パフォーマンスとの兼ね合いを考慮する必要があります
✅ Verification successful
モーション設定は適切な範囲内です
他のモーションファイルとの比較結果から:
- 継続時間4.2秒は、他のモーション(1.6秒~8.57秒)の中で一般的な長さです
- 30FPSはすべてのモーションで統一されており、標準的な設定として問題ありません
- ループ設定(false)も、8つの非ループモーションと1つのループモーションの中で一般的なパターンに従っています
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# 他のモーションファイルの設定と比較
find . -name "*.motion3.json" -exec jq '.Meta.Duration, .Meta.Fps, .Meta.Loop' {} \;
Length of output: 211
src/features/messages/speakQueue.ts (1)
3-4
: インポートの追加は妥当です
Live2D対応のための settingsStore
と Live2DHandler
のインポートは適切です。将来的に関連モジュールが増える場合は、インポートを整理しやすい構造に留意してください。
src/features/messages/live2dHandler.ts (3)
1-4
: Live2D関連のインポート追加
homeStore
と settingsStore
など必要なモジュールがまとめてインポートされており、分かりやすい構成です。
5-7
: idleMotionInterval
の管理が追加
アイドルモーション管理のための idleMotionInterval
をクラスの静的プロパティとして保持している点は、グローバルな管理がしやすく有用です。
🧰 Tools
🪛 Biome (1.9.4)
[error] 5-204: Avoid classes that contain only static members.
Prefer using simple functions instead of classes with only static members.
(lint/complexity/noStaticOnlyClass)
113-132
: アイドルモーション関連のロジック
条件分岐で live2dViewer
が無い場合を考慮しており、エラー回避に配慮しています。なお、過去の指摘どおり、静的コンテキスト内の this.stopIdleMotion()
などはクラス名に置き換えることで可読性が上がります。
🧰 Tools
🪛 Biome (1.9.4)
[error] 125-125: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
src/components/settings/based.tsx (2)
11-37
: 感情設定フィールドの配列定義
emotionFields
の配列で感情を整理しているのは良いアプローチです。インデックスミスなどを避けるためにも、型定義を明確にすると保守性が向上します。
64-153
: Live2DSettingsForm
の設定初期化は有用
マウント時の useEffect
を活用し、空の場合にデフォルトを設定するのは利便性が高いです。今後の要件で追加の感情やモーションが増えたときも拡張しやすい構造です。
src/pages/api/get-live2d-list.ts (1)
1-4
: APIハンドラー用のインポート
NextApiRequest
, NextApiResponse
, fs
, path
を使用しており、不足や過剰な要素は見受けられません。
src/features/stores/home.ts (2)
7-7
: Live2DModel
のインポート
pixi-live2d-display-lipsyncpatch
からのモデルクラス読み込みはLive2D管理に必要不可欠です。具体的な型使用を増やし、エディタでの補完やlint機能を活用できるとさらに良いでしょう。
17-17
: live2dViewer: any
に関する型安全性
過去の指摘と同様に、any
を使うと型安全性が損なわれます。依存ライブラリの型定義を利用したり、型を拡張しておくことを検討してください。
src/components/live2DViewer.tsx (1)
30-35
: コンポーネントのマウント状態を制御する実装がおおむね良好です。
isMounted
フラグで描画を制御するパターンは一般的です。今後、アンマウント処理が必要になる場合は、useEffect のクリーンアップ内でハンドラやイベントリスナーを明示的に解除するよう拡張を検討してください。
public/locales/ja/translation.json (1)
1-4
: Live2D 関連の翻訳キーの追加を確認しました。
キー名「Live2DSettings」は明瞭です。他の翻訳キーと一貫性を保つため、他の Live2D 関連エントリを追加する際はプレフィックスを付与するなどの命名規則を検討してみてください。
.eslintrc.json (1)
7-7
: public/scripts/*
の除外パターンの見直しを推奨
public/scripts/*
配下のすべてのファイルを除外することは、重要なロジックを含むファイルも除外してしまう可能性があります。より具体的な除外パターンの使用を検討してください。
例えば:
- 特定の拡張子のみを除外
- 自動生成されたファイルのみを除外
以下のスクリプトで public/scripts
ディレクトリ内のファイルタイプを確認できます:
✅ Verification successful
public/scripts
の除外パターンは適切です
public/scripts
ディレクトリには以下の特徴が確認されました:
live2d.min.js
とlive2dcubismcore.min.js
の2つのminified JavaScriptファイルのみが含まれています- これらは外部ライブラリの最小化されたファイルであり、ESLintの対象から除外して問題ありません
当初の懸念は解消されました。現在の除外パターン "ignorePatterns": ["public/scripts/*"]
は、minifiedされた外部ライブラリファイルのみを含むディレクトリに対して適切な設定となっています。より具体的なパターンに変更する必要はありません。
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check file types in public/scripts directory
fd . "public/scripts" -t f -x file {} \;
Length of output: 115
Script:
#!/bin/bash
# Check files in public/scripts directory
ls -la public/scripts/ 2>/dev/null || echo "Directory not found"
# Alternative: find files in public/scripts
find public/scripts -type f 2>/dev/null || echo "Directory not found"
# Search for any references to public/scripts in the codebase
rg "public/scripts" -l
Length of output: 403
.vscode/settings.json (1)
1-7
: フォーマッターの設定の整合性を確認
設定自体は適切ですが、以下の点について確認をお願いします:
- Prettier と ESLint の整形ルールが競合していないことを確認
- チーム全体で同じ設定を使用していることを確認
以下のスクリプトで Prettier と ESLint の設定の整合性を確認できます:
✅ Verification successful
フォーマッター設定は適切に構成されています
以下の点から、Prettier と ESLint の設定が適切に構成されていることを確認できました:
eslint-config-prettier
が devDependencies に正しくインストールされています- ESLint の設定で
"prettier"
が extends に含まれており、競合を防止しています .prettierrc.json
の設定内容は標準的で問題ありません- VS Code の設定(
editor.defaultFormatter
とeditor.formatOnSave
)は Prettier の設定と整合しています
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for potential formatting conflicts
# Check if there are any conflicting rules between Prettier and ESLint
cat .eslintrc.json | jq '.rules | keys[]'
cat .prettierrc 2>/dev/null || echo "Prettierrc not found"
Length of output: 132
Script:
#!/bin/bash
# Check for eslint-config-prettier in package.json and any ESLint extends
cat package.json | jq '.dependencies["eslint-config-prettier"], .devDependencies["eslint-config-prettier"]'
cat .eslintrc.json | jq '.extends'
Length of output: 201
Script:
#!/bin/bash
# Check for prettier config in package.json
cat package.json | jq '.prettier'
Length of output: 38
Script:
#!/bin/bash
# Look for any other prettier config files
fd -e yml -e yaml -e json -e js -e config.js -e rc.js -H "prettier"
Length of output: 84
Script:
#!/bin/bash
# Check contents of .prettierrc.json
cat .prettierrc.json
Length of output: 114
public/live2d/nike01/expressions/NoSmile.exp3.json (1)
1-16
: Live2D表情パラメータの一貫性確認
表情パラメータの設定は適切ですが、以下の点について確認をお願いします:
FadeInTime
の 0.75 秒が他の表情ファイルと一貫しているかParamMouthForm
とParamHairpinChange
のパラメータ値が適切な範囲内か- 他の表情ファイルでも同じパラメータ名を使用しているか
以下のスクリプトで表情ファイル間の一貫性を確認できます:
✅ Verification successful
Live2D表情パラメータの一貫性を確認しました
表情ファイルの分析結果に基づき、以下の点を報告いたします:
-
FadeInTime
は大半のファイルで0.75秒に設定されており、一貫性が保たれています。ただし、一部のファイルで値が設定されていない(null)ケースがあります。 -
パラメータの使用状況:
ParamMouthForm
: -1から1の範囲内で適切に設定されていますParamHairpinChange
: すべての表情で一貫して1に設定されています
- パラメータの組み合わせは表情ごとに適切に変化しており、Live2Dの表現として問題ありません。
推奨事項:
- nullとなっている
FadeInTime
を0.75秒に統一することをご検討ください - その他のパラメータ設定は適切で一貫性が保たれているため、現状のまま問題ありません
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check consistency across expression files
# List all expression files and their parameters
fd . "public/live2d" -e exp3.json -x jq -r '["File: \(.Type)", "FadeIn: \(.FadeInTime)", (.Parameters[] | "Param: \(.Id) Value: \(.Value) Blend: \(.Blend)")][]' {}
Length of output: 3799
public/live2d/nike01/items_pinned_to_model.json (1)
9-13
: シーン関連フィールドが未設定です
シーン名、グループ名、モデル、IDがすべて空白になっています。これらの値が意図的に空白なのか、それとも設定が必要なのかを確認してください。空白のままですと、将来的なモデルの管理や識別が困難になる可能性があります。
必要な場合は、適切なシーン設定値の例を提供させていただきます。
public/live2d/nike01/expressions/Neutral.exp3.json (1)
1-26
: パラメータの命名規則と値の範囲の検証が必要です
以下の点について確認をお願いします:
- パラメータIDの命名規則が統一されているか
- 各パラメータの有効な値の範囲(特に0-1の範囲内であるべきか)
ParamHairpinChange
の値が1である理由
✅ Verification successful
パラメータの検証が完了しました - 問題ありません
検証結果に基づき、以下の点が確認できました:
- パラメータIDの命名規則は全ての表情ファイルで一貫して使用されています
- パラメータ値は全て0-1の範囲内に収まっており、適切です:
ParamAngerBrows
: 0-0.663ParamTroubleBrows
: 0-1ParamHeMouth
: 0-1
ParamHairpinChange
の値が1であることは、他の全ての表情設定でも同様であり、意図的な設定と判断できます
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# 他の表情設定ファイルでのパラメータ名と値の範囲を確認
rg -l "ParamHairpinChange|ParamAngerBrows|ParamTroubleBrows|ParamHeMouth" public/live2d/nike01/expressions/
Length of output: 810
Script:
#!/bin/bash
# Check parameter values in other expression files
rg -A 2 "ParamHairpinChange|ParamAngerBrows|ParamTroubleBrows|ParamHeMouth" public/live2d/nike01/expressions/
Length of output: 7063
public/live2d/nike01/expressions/Troubled.exp3.json (1)
1-26
: 表情の一貫性とテストの必要性について
以下の点について検討をお願いします:
- 複数のパラメータ(眉毛、口)の組み合わせによる表情の検証
- 他の表情(特に
Sad.exp3.json
)との違いの明確化 - パラメータ値の精度の統一(0.471や0.346など)
表情設定のバリデーションと自動テストの仕組みの導入を検討してください。
✅ Verification successful
Let me generate another verification script to get more details about the parameter IDs and their values specifically in Sad.exp3.json for comparison.
表情パラメータの設定に関する確認結果
検証の結果、以下の点が確認できました:
-
Troubled.exp3.json
の表情設定は適切に実装されています:ParamTroubleBrows
とParamAngerBrows
の組み合わせにより、微妙な眉の表現を実現ParamHeMouth
の値(0.471)は他の表情との差別化に貢献
-
Sad.exp3.json
およびSad2.exp3.json
との比較:- 明確な差異が確認できます
- 「困った」表情は怒りの要素を含む独自の組み合わせを使用
- 「悲しい」表情とは異なるパラメータセットを使用
-
パラメータ値の精度については:
- 現状の小数点以下3桁の精度は、Live2Dの表現において一般的で適切
- 他の表情設定ファイルでも同様の精度が使用されています
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# 表情パラメータの重複や矛盾を確認
rg -A 2 '"Value": [0-9.]+' public/live2d/nike01/expressions/*.exp3.json
Length of output: 10852
Script:
#!/bin/bash
# Get full content of Sad.exp3.json and Sad2.exp3.json for comparison
cat public/live2d/nike01/expressions/Sad.exp3.json public/live2d/nike01/expressions/Sad2.exp3.json
Length of output: 1020
public/live2d/nike01/expressions/Zitome.exp3.json (1)
1-30
: 表情パラメータの命名と値の検証について
表情定義ファイルについて、以下の点を確認・改善することを推奨します:
- ファイル名の
Zitome
は「じとめ」を意味すると思われますが、より明確な英語名(例:Sullen
やGlare
)の使用を検討してください - パラメータ値の範囲が適切か確認が必要です:
ParamEyeLOpen
とParamEyeROpen
の-0.4という値ParamMouthForm
の-1という値
表情パラメータの有効範囲を定義したスキーマファイルの作成を検討してください。これにより、不正な値の設定を防ぐことができます。
✅ Verification successful
表情パラメータの値は適切な範囲内です
他の表情ファイルの調査結果から、現在の実装は問題ありません:
ParamEyeLOpen
とParamEyeROpen
は-1から0の範囲で使用されています(例:Sleep.exp3.jsonで-1、Think.exp3.jsonで-0.158)ParamMouthForm
は-1から1の範囲で使用されています(例:Happy.exp3.jsonで1、NoSmile.exp3.jsonで-1)
ファイル名の「Zitome」については、Live2D実装での日本語表現の一般的な慣習として問題ないと判断します。
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# 他の表情ファイルでの同様のパラメータ値の範囲を確認
rg -A 1 "ParamEyeLOpen|ParamEyeROpen|ParamMouthForm" public/live2d/nike01/expressions/
Length of output: 2825
public/live2d/nike01/expressions/Sad2.exp3.json (1)
1-31
: 🛠️ Refactor suggestion
表情バリエーションの管理と値の検証について
表情ファイルについて、以下の改善点があります:
-
命名規則:
Sad2
という名前は表情の違いが不明確です- より具体的な名前(例:
DeeplySad
、SlightlySad
)の使用を推奨します
-
パラメータ設定:
FadeInTime
の0.75秒が適切か検証が必要ですParamAngleZ
の14.471という値は精度が高すぎる可能性があります
表情定義の管理を改善するため、以下の対応を推奨します:
- 表情の命名規則の文書化
- パラメータ値の有効範囲の定義
- 類似表情(Sad、Sad2など)の違いを説明するドキュメントの作成
表情定義の管理方針とドキュメントテンプレートの作成をお手伝いしましょうか?
public/live2d/nike01/expressions/Think2.exp3.json (1)
1-31
: 表情パラメータの設定が適切です
Think2表情の設定内容を確認しました:
- フェードイン時間(0.75秒)は自然な表情変化に適しています
- 各パラメータの値は思考中の表情として適切な範囲内です
- 必要なパラメータがすべて含まれています
public/live2d/nike01/motions/Motion9.motion3.json (1)
1-25
: モーション設定が適切に構成されています
モーション設定の内容を確認しました:
- バージョン3の仕様に準拠しています
- メタデータ(FPS、ループ設定など)が適切に設定されています
- セグメント数とポイント数が正確に記録されています
public/live2d/nike01/expressions/Sleep.exp3.json (1)
1-35
: 睡眠表情の設定が適切です
Sleep表情の設定内容を確認しました:
- 両目を閉じる設定(ParamEyeLOpen、ParamEyeROpen)が-1に設定されており適切です
- 口の形状(ParamMouthForm)が自然な閉じた状態になっています
- すべての必要なパラメータが含まれています
public/live2d/nike01/expressions/Happy2.exp3.json (1)
1-36
: 表情パラメータの設定が適切です!
笑顔の表情として自然な設定になっています。以下の特徴が確認できます:
- 目を細める(ParamEyeLSmile、ParamEyeRSmile)
- 口角を上げる(ParamMouthForm)
- 自然な目の開き具合
src/pages/index.tsx (1)
8-8
: 新しいコンポーネントのインポートが適切に追加されています!
Live2DViewerコンポーネントのインポートが正しく行われています。
kyarasettei.txt (1)
51-52
: タイムゾーン処理の明確化が必要
タイムゾーンがポーランドと指定されていますが、以下の点について追加の指定が必要です:
- 夏時間の扱い
- 日本時間との変換ルール
- 時差を考慮した朝昼夜の判断基準
package.json (1)
48-49
: 依存関係の検証結果と推奨事項
-
pixi-live2d-display-lipsyncpatch
について:- 循環依存関係が検出されました
- バージョン範囲指定(
^
)の使用に注意が必要です
-
pixi.js
について:- コアライブラリとして使用されています
- バージョンの固定を推奨します
public/live2d/nike01/nike01.model3.json (1)
4-7
: ファイルパスの検証が必要
モデルファイルとテクスチャファイルへの参照が正しいか確認してください。特に高解像度テクスチャ(8192)の使用は、パフォーマンスに影響を与える可能性があります。
✅ Verification successful
ファイルパスの参照は正しく設定されています
すべての必要なファイルが正しい場所に存在することを確認しました:
- モデルファイル(nike01.moc3)
- 物理演算ファイル(nike01.physics3.json)
- ディスプレイ情報ファイル(nike01.cdi3.json)
- テクスチャファイル(nike01.8192/texture_00.png)
ただし、8192サイズのテクスチャを使用していることについて、以下の点に注意してください:
- モバイルデバイスでのメモリ使用量が増加
- 初期ロード時間の増加
- 一般的なユースケースでは4096や2048サイズで十分な品質が得られる
パフォーマンスの最適化が必要な場合は、より小さいテクスチャサイズの使用を検討することをお勧めします。
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# モデルファイルとテクスチャファイルの存在を確認
fd -t f "nike01\.(moc3|physics3\.json|cdi3\.json)$|texture_00\.png$" public/live2d/nike01
Length of output: 252
src/components/Live2DComponent.tsx (1)
76-108
: エラーハンドリングの改善が必要
モデルのロード失敗時のエラーハンドリングが不十分です。
public/live2d/nike01/motions/Motion4.motion3.json (1)
4-13
: アニメーション設定が適切です
以下の点が特に良好です:
- 目のまばたきのタイミングが自然
- 体の動きの連携が適切
- 髪の動きによる二次的なモーションの追加
public/live2d/nike01/motions/Motion7.motion3.json (1)
4-13
: モーションの長さと構成が最適です
短い反応アニメーションとして適切な設定になっています:
- 1.6秒の長さは素早い反応として最適
- セグメント数とポイント数が適切
public/live2d/nike01/motions/Motion5.motion3.json (5)
4-12
: モーション設定の基本パラメータを確認しました
- 8.57秒の長いモーションです
- FPSは30.0で標準的な設定です
- ループが無効化されているため、一回限りの再生となります
14-47
: 頭の角度パラメータ(X, Y, Z)の設定を確認
アニメーションカーブの設定が適切で、自然な頭の動きを実現しています。特にParamAngleXの-30度から0度への変化が滑らかです。
77-151
: 目のパラメータ設定について
目のパラメータ(開閉、視線移動)が適切に設定されており、自然な目の動きを実現しています。まばたきのタイミングも自然です。
152-205
: 体の動きのパラメータについて
体の角度パラメータ(X, Y, Z)の設定が適切で、動きに抑揚があり生き生きとした印象を与えています。
206-246
: 腕と髪の動きについて
腕の動きと髪の揺れが連動しており、自然な動きを実現しています。特にParamHairAhogeの動きが表情や体の動きと同期していて効果的です。
locales/ja/translation.json (2)
50-50
: キャラクター設定の説明文が分かりやすく記述されています
感情タグの使用例が含まれており、ユーザーが理解しやすい説明となっています。
207-225
: Live2D関連の翻訳が適切に追加されています
感情とモーションの設定に関する説明が詳細で、初めてのユーザーでも理解しやすい内容となっています。
locales/ko/translation.json (1)
207-224
: 日本語版と韓国語版の翻訳の一貫性を確認しました
Live2D関連の翻訳が日本語版と同じ構造で適切に実装されており、両言語間で一貫性が保たれています。
src/features/stores/settings.ts (1)
305-317
: Live2D設定の初期化処理について
前回のレビューで指摘された問題が解決されていません:
- 空文字列の環境変数が
split(',')
により[""]
となる問題 - モーショングループの値の検証が不足している問題
以下の修正を再度推奨します:
// Live2D settings
neutralEmotions:
- process.env.NEXT_PUBLIC_NEUTRAL_EMOTIONS?.split(',') || [],
+ (process.env.NEXT_PUBLIC_NEUTRAL_EMOTIONS || '').split(',').filter(Boolean) || [],
// 他の感情配列も同様に
public/live2d/nike01/motions/Motion8.motion3.json (2)
1-13
: メタデータの設定が適切です
アニメーションの基本パラメータ(バージョン、継続時間、FPS、ループ設定など)が適切に構成されています。
1-188
: 他のモーションファイルとの整合性の確認
このモーションファイルが他のLive2Dモーションと適切に連携できることを確認してください。以下の点に注意してください:
- 他のモーションとの切り替え時の自然な遷移
- パラメータ範囲の一貫性
- モーション間の表現の統一性
✅ Verification successful
モーションパラメータの範囲は適切で整合性が取れています
他のモーションファイルとの比較分析の結果、Motion8.motion3.jsonのパラメータ範囲は以下の点で適切です:
- 角度パラメータ(AngleX/Y/Z)は他のモーションと同様の範囲内(-30°~30°)に収まっています
- 目や口の開閉(EyeOpen/MouthOpenY)のパラメータ範囲は標準的です
- 体の動き(BodyAngle)も他のモーションと同様の自然な範囲です
- 腕の動き(ArmLA/RA)は全モーションで統一された-10の最小値を使用しています
このモーションファイルは他のLive2Dモーションとスムーズに連携できる設計になっています。
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: 他のLive2Dモーションファイルとのパラメータ範囲の比較
# 同じディレクトリ内の他のモーションファイルを検索
echo "Checking parameter ranges in other motion files..."
for motion in $(fd -e motion3.json . public/live2d/nike01/motions/); do
echo "Analyzing $motion"
# パラメータの範囲を抽出して比較
jq -r '.Curves[] | select(.Target == "Parameter") | "\(.Id): \(.Segments | [.[]] | [min,max])"' "$motion"
done
Length of output: 7418
"Segments": [ | ||
0, 0, 1, 0.056, 0, 0.111, 0, 0.167, 0, 1, 0.244, 0, 0.322, -4, 0.4, -4, | ||
1, 0.478, -4, 0.556, 10, 0.633, 10, 1, 0.8, 10, 0.967, -0.386, 1.133, | ||
-0.386, 1, 1.244, -0.386, 1.356, 10, 1.467, 10, 1, 1.6, 10, 1.733, 0, | ||
1.867, 0, 1, 2.044, 0, 2.222, 10, 2.4, 10, 1, 2.444, 10, 2.489, 10.395, | ||
2.533, 9.649, 1, 2.7, 6.854, 2.867, -3.526, 3.033, -3.526, 1, 3.267, | ||
-3.526, 3.5, 6.807, 3.733, 6.807, 1, 3.811, 6.807, 3.889, 6, 3.967, 6, | ||
0, 4.2, 6 | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
体の動きが急激すぎる可能性があります
ParamBodyAngleYのセグメントにおいて、以下の問題が見られます:
- 値の変化が急激(-4から10への急な変化)
- モーション後半の揺れが大きすぎる可能性があります
より自然な動きにするために、以下の修正を提案します:
"Segments": [
0, 0, 1, 0.056, 0, 0.111, 0, 0.167, 0, 1, 0.244, 0, 0.322, -4, 0.4, -4,
- 1, 0.478, -4, 0.556, 10, 0.633, 10, 1, 0.8, 10, 0.967, -0.386, 1.133,
+ 1, 0.478, -4, 0.556, 6, 0.633, 6, 1, 0.8, 6, 0.967, -0.386, 1.133,
-0.386, 1, 1.244, -0.386, 1.356, 10, 1.467, 10, 1, 1.6, 10, 1.733, 0,
1.867, 0, 1, 2.044, 0, 2.222, 10, 2.4, 10, 1, 2.444, 10, 2.489, 10.395,
2.533, 9.649, 1, 2.7, 6.854, 2.867, -3.526, 3.033, -3.526, 1, 3.267,
-3.526, 3.5, 6.807, 3.733, 6.807, 1, 3.811, 6.807, 3.889, 6, 3.967, 6,
0, 4.2, 6
]
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"Segments": [ | |
0, 0, 1, 0.056, 0, 0.111, 0, 0.167, 0, 1, 0.244, 0, 0.322, -4, 0.4, -4, | |
1, 0.478, -4, 0.556, 10, 0.633, 10, 1, 0.8, 10, 0.967, -0.386, 1.133, | |
-0.386, 1, 1.244, -0.386, 1.356, 10, 1.467, 10, 1, 1.6, 10, 1.733, 0, | |
1.867, 0, 1, 2.044, 0, 2.222, 10, 2.4, 10, 1, 2.444, 10, 2.489, 10.395, | |
2.533, 9.649, 1, 2.7, 6.854, 2.867, -3.526, 3.033, -3.526, 1, 3.267, | |
-3.526, 3.5, 6.807, 3.733, 6.807, 1, 3.811, 6.807, 3.889, 6, 3.967, 6, | |
0, 4.2, 6 | |
] | |
"Segments": [ | |
0, 0, 1, 0.056, 0, 0.111, 0, 0.167, 0, 1, 0.244, 0, 0.322, -4, 0.4, -4, | |
1, 0.478, -4, 0.556, 6, 0.633, 6, 1, 0.8, 6, 0.967, -0.386, 1.133, | |
-0.386, 1, 1.244, -0.386, 1.356, 10, 1.467, 10, 1, 1.6, 10, 1.733, 0, | |
1.867, 0, 1, 2.044, 0, 2.222, 10, 2.4, 10, 1, 2.444, 10, 2.489, 10.395, | |
2.533, 9.649, 1, 2.7, 6.854, 2.867, -3.526, 3.033, -3.526, 1, 3.267, | |
-3.526, 3.5, 6.807, 3.733, 6.807, 1, 3.811, 6.807, 3.889, 6, 3.967, 6, | |
0, 4.2, 6 | |
] |
@@ -0,0 +1,35 @@ | |||
{ | |||
"Type": "Live2D Expression", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
FadeInTimeプロパティの追加を推奨
他の表情設定ファイル(例:Think2.exp3.json)と同様に、自然な表情遷移のためにFadeInTime
プロパティの追加を推奨します:
{
"Type": "Live2D Expression",
+ "FadeInTime": 0.75,
"Parameters": [
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"Type": "Live2D Expression", | |
"Type": "Live2D Expression", | |
"FadeInTime": 0.75, |
src/components/Live2DComponent.tsx
Outdated
useEffect(() => { | ||
if (!app || !model) return | ||
|
||
const onResize = () => { | ||
if (!canvasContainerRef.current) return | ||
|
||
app.renderer.resize( | ||
canvasContainerRef.current.clientWidth, | ||
canvasContainerRef.current.clientHeight | ||
) | ||
|
||
setModelPosition(app, model) | ||
} | ||
window.addEventListener('resize', onResize) | ||
|
||
return () => { | ||
window.removeEventListener('resize', onResize) | ||
} | ||
}, [app, model]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
リサイズハンドラの最適化
リサイズイベントの頻発を防ぐためのデバウンス処理が必要です。
+import { debounce } from 'lodash'
+
useEffect(() => {
if (!app || !model) return
- const onResize = () => {
+ const onResize = debounce(() => {
if (!canvasContainerRef.current) return
app.renderer.resize(
canvasContainerRef.current.clientWidth,
canvasContainerRef.current.clientHeight
)
setModelPosition(app, model)
- }
+ }, 250)
window.addEventListener('resize', onResize)
return () => {
window.removeEventListener('resize', onResize)
+ onResize.cancel()
}
}, [app, model])
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
useEffect(() => { | |
if (!app || !model) return | |
const onResize = () => { | |
if (!canvasContainerRef.current) return | |
app.renderer.resize( | |
canvasContainerRef.current.clientWidth, | |
canvasContainerRef.current.clientHeight | |
) | |
setModelPosition(app, model) | |
} | |
window.addEventListener('resize', onResize) | |
return () => { | |
window.removeEventListener('resize', onResize) | |
} | |
}, [app, model]) | |
useEffect(() => { | |
if (!app || !model) return | |
const onResize = debounce(() => { | |
if (!canvasContainerRef.current) return | |
app.renderer.resize( | |
canvasContainerRef.current.clientWidth, | |
canvasContainerRef.current.clientHeight | |
) | |
setModelPosition(app, model) | |
}, 250) | |
window.addEventListener('resize', onResize) | |
return () => { | |
window.removeEventListener('resize', onResize) | |
onResize.cancel() | |
} | |
}, [app, model]) |
"Segments": [ | ||
0, 1, 1, 0.556, 1, 1.111, 1, 1.667, 1, 1, 1.711, 1, 1.756, 0, 1.8, 0, 1, | ||
1.822, 0, 1.844, 0, 1.867, 0, 1, 1.911, 0, 1.956, 1, 2, 1, 1, 2.489, 1, | ||
2.978, 1, 3.467, 1, 1, 3.511, 1, 3.556, 0, 3.6, 0, 1, 3.622, 0, 3.644, | ||
0, 3.667, 0, 1, 3.733, 0, 3.8, 1, 3.867, 1, 0, 4.7, 1 | ||
] | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
目のパラメータが同期していません
ParamEyeLOpen
とParamEyeROpen
のパラメータは同じ動きをするべきですが、別々に定義されています。
メンテナンス性を向上させるため、これらのパラメータを統一することを推奨します。また、まばたきのタイミングをより自然にするため、ランダム性を持たせることも検討してください。
interface Live2DSettings { | ||
neutralEmotions: string[] | ||
happyEmotions: string[] | ||
sadEmotions: string[] | ||
angryEmotions: string[] | ||
relaxedEmotions: string[] | ||
idleMotionGroup: string | ||
neutralMotionGroup: string | ||
happyMotionGroup: string | ||
sadMotionGroup: string | ||
angryMotionGroup: string | ||
relaxedMotionGroup: string | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Live2DSettingsインターフェースの型安全性について
感情とモーションの設定に関するインターフェースが追加されていますが、以下の点について改善が必要です:
- 感情配列の型が単純な
string[]
となっており、有効な感情値の制約がありません - モーショングループの型チェックが不足しています
以下のような改善を推奨します:
+type Emotion = 'neutral' | 'happy' | 'sad' | 'angry' | 'relaxed';
+type MotionGroup = 'idle' | 'neutral' | 'happy' | 'sad' | 'angry' | 'relaxed';
interface Live2DSettings {
- neutralEmotions: string[]
+ neutralEmotions: Emotion[]
// 他の感情配列も同様に
- idleMotionGroup: string
+ idleMotionGroup: MotionGroup
// 他のモーショングループも同様に
}
Committable suggestion skipped: line range outside the PR's diff.
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
🧹 Nitpick comments (60)
public/live2d/nike01/motions/Motion4.motion3.json (2)
14-125
: 頭部・表情モーションの最適化提案頭部と表情のパラメータは論理的に設定されていますが、以下の改善点があります:
- ParamAngleX/Y/Zの急激な変化(例:line 19-21)により不自然な動きが発生する可能性
- 目のパラメータ(ParamEyeLOpen/ROpen)が完全に同期しており、より自然な非対称性を付加することを推奨
目のパラメータに微細な時間差やわずかな開き具合の違いを追加することで、よりリアルな表情を実現できます。
149-167
: 呼吸と腕のモーションについて呼吸のパラメータ(ParamBreath)は適切に設定されていますが、腕の設定に改善の余地があります:
- 両腕(ParamArmLA/RA)が固定値(-10)に設定されており、動きが欠如
- 呼吸に合わせた微細な腕の動きが望ましい
腕のパラメータに呼吸と連動した微細な動きを追加することで、よりリアルな表現が可能です。
public/live2d/nike01/motions/Motion8.motion3.json (3)
1-13
: モーションの長さを標準化することを推奨します現在のモーションの長さは4.17秒となっていますが、再生時のループを考慮すると、より標準的な長さ(例:4秒や5秒)に調整することで、他のモーションとの連携がスムーズになる可能性があります。
42-93
: 目の動きの同期性について左右の目(ParamEyeLOpen、ParamEyeROpen)のパラメータが完全に同一の値で設定されています。自然な表情のために、わずかな非対称性を持たせることを検討してください。また、まばたきのタイミングをより自然にするため、セグメント数を減らすことで滑らかさを向上できる可能性があります。
153-172
: 腕の動きのバリエーションについて左右の腕(ParamArmLA、ParamArmRA)の動きがほぼ同一です。より自然な表現のために:
- 左右の腕で異なるタイミングの動きを設定
- 動きの範囲を腕ごとに調整
- より細かいセグメントを追加して表現の幅を広げる
これらの改善により、よりダイナミックな動きが実現できます。
public/live2d/nike01/motions/Motion9.motion3.json (2)
19-21
: セグメント配列の可読性を改善してくださいセグメント配列が1行に詰め込まれており、可読性が低下しています。時間と値のペアを明確に区別できるように、配列を整形することを推奨します。
以下のような形式に整理することをお勧めします:
- 0, 0, 1, 0.111, 0, 0.222, -15, 0.333, -15, 1, 0.444, -15, 0.556, 15, - 0.667, 15, 1, 0.778, 15, 0.889, -15, 1, -15, 1, 1.111, -15, 1.222, 15, - 1.333, 15, 1, 1.433, 15, 1.533, 2.85, 1.633, 0.42 + [ + [0, 0, 1], + [0.111, 0, 0.222], + [0.333, -15, 1], + [0.444, -15, 0.556], + [0.667, 15, 1], + [0.778, 15, 0.889], + [1, -15, 1], + [1.111, -15, 1.222], + [1.333, 15, 1], + [1.433, 15, 1.533], + [1.633, 0.42] + ]
16-22
: モーションの自然さを改善するための提案現在のモーションには以下の潜在的な問題があります:
ParamAngleX
の値が-15から+15まで急激に変化しており、不自然な動きになる可能性があります。- 極端な値の間の遷移が急すぎる可能性があります。
以下の改善を検討してください:
- 角度の範囲を-10から+10程度に抑えることで、より自然な頭の動きを表現できます。
- イージング関数を使用して、極端な値の間の遷移をよりスムーズにすることを推奨します。
src/features/messages/speakQueue.ts (3)
27-27
: ローカル変数名の簡潔さについて
ss
は機能をよく表していますが、より明確にsettingsState
などの命名にすると可読性が上がる可能性があります。
33-37
: モデル種別に応じた分岐処理
modelType === 'live2d'
の場合にLive2DHandler.speak
を呼び出し、それ以外は既存のメソッドを呼び出す実装はわかりやすいです。将来的にモデル種別が増えた場合の拡張性を考えて、スイッチ文やマッピングテーブルでの実装も検討ください。
63-64
: 再度のストア取得
同じスコープ内で繰り返しsettingsStore.getState()
を呼び出すコストは小さいですが、パフォーマンスを最大限重視するなら、一度だけ取得した結果を使い回すことも視野に入れてください。src/components/Live2DComponent.tsx (3)
1-10
: import とデバッグログ
PIXI や React、独自のハンドラといった依存を正しくインポートしており問題ありません。console.log
はデバッグ目的だと思いますが、本番ビルドでは不要であれば削除することを推奨します。
11-20
: モデル位置設定のユーティリティ
setModelPosition
はシンプルに中心配置とスケーリングを行っており、再利用性が高い関数です。スケール値0.3
は定数として外部に切り出すと、今後の調整が容易になります。
47-61
: モデル再読込フロー
古いモデルインスタンスを破棄してステージリセット後、新モデルを読み込むフローは明快です。ただし、読込時エラーが起きた場合のリトライやユーザー通知なども検討するとユーザー体験が向上します。src/features/messages/live2dHandler.ts (5)
52-69
: AudioContext の初期化と音声デコード処理
エラーハンドリングは最低限なされていますが、audioContext.decodeAudioData
に失敗した場合のユーザー向け通知があるとさらに良いです。
71-85
: OfflineAudioContext でのレンダリング
非同期で音声を合成し、WAV に変換しているアプローチは興味深い実装です。モバイル環境や古い端末での互換性も考慮できると安心です。
113-132
:resetToIdle
メソッド
アイドルモーションと表情を設定する流れが分かりやすいです。アイドルモーション切替の頻度を変更したい場面が多い場合、コンフィグとして外部から指定できるように実装すると拡張性が高まります。🧰 Tools
🪛 Biome (1.9.4)
[error] 125-125: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.(lint/complexity/noThisInStatic)
134-139
:startIdleMotion
のアイドルモーション周期
5秒ごとにモーションを発火する設計は適切ですが、モデルによってはモーションが完了する前に次が呼ばれる可能性があるため、モデル側のモーション状態を確認しながら間隔を調整できるとより安定動作が期待できます。
149-202
: WAV 変換ヘルパー関数
マルチチャンネルに対応し、ヘッダーを手動で書き込む低レベル実装は高度です。関数単体のテストを実装しておくと、音声が破損した際に原因を特定しやすくなるでしょう。🧰 Tools
🪛 Biome (1.9.4)
[error] 151-151: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.(lint/complexity/noThisInStatic)
[error] 157-157: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.(lint/complexity/noThisInStatic)
[error] 161-161: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.(lint/complexity/noThisInStatic)
[error] 161-162: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.(lint/complexity/noThisInStatic)
src/components/settings/based.tsx (2)
11-37
: 感情設定フィールドの定義
emotionFields
にデフォルト値を含めた配列を用意し、UIで修正可能にしている点は明確です。ただし、感情名が固定文字列のため、タイプセーフが必要なら TypeScript の列挙型なども検討してください。
64-154
:Live2DSettingsForm
コンポーネント
マウント時にデフォルト値を補完したり、カンマ区切りで入力を配列化する実装は分かりやすいです。重複や空文字の除外などのロジックを追加すると、意図しない値を防げます。src/features/stores/settings.ts (3)
45-57
:Live2DSettings
インターフェース
感情配列とモーション設定のプロパティを明確に定義しています。空文字列を除外するなどのバリデーションが必要な場合は、ここで型レベルも強化すると保守性が上がります。
136-138
:modelType
enum風型
'vrm' | 'live2d'
という組み合わせは分かりやすいですが、増加した場合に拡張しやすい形態で定義(E.g. Union 型の列挙)しておくと将来対応が容易です。
248-250
: "/live2d/nike01/nike01.model3.json
" というデフォルト
デフォルトモデルのパスがハードコードされています。デフォルトが変更される可能性を考慮し、環境変数や別ファイルでの設定を検討すると柔軟に対応できます。src/pages/api/get-live2d-list.ts (2)
21-34
: 同期的なファイルチェックや I/O のエラー処理をより強固にする提案
フォルダ内に.model3.json
が複数存在するケースや、OS/ファイルシステムによってはファイル名の大文字小文字差分などがあり得るため、必要に応じてフィルタリングを拡張することが検討できます。
36-42
: エラー内容の詳細ログ出力について
console.error
でスタックトレースなどの詳細が出る場合でも、サーバーログでトラブルシューティングしやすいよう、可能であればエラーオブジェクトのプロパティ(例:message
など)を追記するとデバッグが容易になります。src/pages/index.tsx (2)
20-20
: modelType に対するデフォルト値やバリデーションを検討
modelType
が未設定の場合の動作をチェックし、デフォルトのモデル表示やエラーハンドリングを考慮すると、ユーザー体験の向上につながります。
26-26
: VRM と Live2D で UI レイアウトが大きく異なる可能性への検討
VRM と Live2D のモデル全体の画面配置・UI が異なるので、もし将来的にログイン前後やデバイス幅によって動作が変更となる場合は、レスポンシブレイアウトを切り替える仕組みを追加することも検討できます。src/features/stores/home.ts (1)
68-72
: セット関数の再利用 & ロジック共通化の提案
setIsCubismCoreLoaded
とsetIsLive2dLoaded
が類似のパターンを持つため、まとめて管理するユーティリティ関数などを導入すればコード重複を減らすことが期待できます。src/components/live2DViewer.tsx (4)
8-28
: Dynamic Import のエラー処理が適切
import('./Live2DComponent')
のcatch
節でログを出していますが、画面側でユーザー向けのエラー状態を表示する方法もあると、ユーザービリティが高まるかもしれません。
30-35
: リトライ回数と閾値の管理
scriptLoadRetries
による再読み込みを行う設計は良いですが、ロード失敗が繰り返される原因に応じては追加ログやユーザーへの通知が必要になるかもしれません。
66-67
: フルスクリーンレイアウトの固定化
bottom-0 right-0 w-screen h-screen
として全画面を固定しているため、他コンポーネントとの競合について要確認です。場合によってはコンテナ要素を分割し、レスポンシブ対応が検討できるかもしれません。
86-104
: Core と Live2D スクリプトロードの依存関係を可視化
isCubismCoreLoaded
が true の場合にのみlive2d.min.js
を読み込む設計は理解しやすいですが、将来的にスクリプトの依存構造が複雑化する可能性があるため、ロード順や失敗時のフォールバック処理を管理する仕組みを検討すると拡張性が高まります。src/features/messages/speakCharacter.ts (1)
267-273
: AivisSpeechのLive2D再生ロジックを確認
testAivisSpeech
でも同様の切り替え処理が導入されています。複数の音声エンジンを切り替える際にメモリリークやイベント競合が起こらないよう、Live2DHandler側のライフサイクル管理・リソース管理を再度ご確認ください。.eslintrc.json (1)
6-7
: 特定ディレクトリのESLint除外設定に注意
"ignorePatterns": ["public/scripts/*"]
でpublic/scripts
配下を除外しています。ビルド後のアセットや外部スクリプトを想定している場合は問題ありませんが、もしビジネスロジックに影響するスクリプトが含まれている場合は、Lintツールによる検証漏れに注意が必要です。public/live2d/nike01/items_pinned_to_model.json (1)
2-8
: メタデータの更新方針を確認してくださいファイルメタデータについて以下の点を検討してください:
- VTube Studioのバージョン管理方針
- タイムスタンプの自動更新の仕組み
- プラットフォーム情報の管理方法
メタデータの更新を自動化するメカニズムの導入を検討してください。
public/live2d/nike01/expressions/Happy.exp3.json (1)
1-26
: パラメータ値の調整と文書化の推奨すべてのパラメータ値が1.0に設定されており、表情が強すぎる可能性があります。より自然な表情のために、以下の改善を提案します:
ParamMouthForm
とParamEyeRSmile
/ParamEyeLSmile
の値を0.7-0.8程度に調整- 各パラメータの役割と想定される値の範囲をコメントとして追加
以下のような形式でコメントを追加することを推奨します:
{ "Type": "Live2D Expression", "FadeInTime": 0.75, + "Description": "通常の笑顔表現", + "Notes": " + - ParamMouthForm: 口の形状(推奨範囲: 0.0-1.0) + - ParamHairpinChange: ヘアピンの状態(0: 通常, 1: 変化) + - ParamEyeRSmile: 右目の笑顔(推奨範囲: 0.0-1.0) + - ParamEyeLSmile: 左目の笑顔(推奨範囲: 0.0-1.0) + ", "Parameters": [.gitignore (1)
51-52
: Live2Dモデル管理戦略の提案Live2Dモデルの管理方法について、以下の点を考慮することを推奨します:
- モデルのバージョン管理戦略を文書化
- 商用ライセンスや著作権情報の管理方法を明確化
- 将来的な追加モデルの管理方針を決定
public/live2d/* !public/live2d/nike01 +!public/live2d/README.md
上記の変更を適用し、
README.md
にモデル管理方針を記載することを提案します。以下の内容を含めることを推奨します:
- ライセンス情報
- モデルの追加・更新手順
- ディレクトリ構造の説明
public/live2d/nike01/expressions/Zitome.exp3.json (1)
1-30
: FadeInTimeプロパティの追加を推奨他の表情設定ファイルとの一貫性を保つため、FadeInTimeプロパティを追加することを推奨します。突然の表情変化を防ぎ、よりスムーズな遷移を実現できます。
{ "Type": "Live2D Expression", + "FadeInTime": 0.75, "Parameters": [
また、パラメータ値は適切に設定されており、目を細める表情をよく表現できています。
public/live2d/nike01/expressions/Sad2.exp3.json (1)
1-31
: パラメータ値の小数点以下の精度を統一することを推奨パラメータ値の小数点以下の精度にばらつきがあります:
- ParamAngleZ: 14.471(小数点以下3桁)
- ParamHeMouth: 0.929(小数点以下3桁)
- ParamMouthOpenY: 0.259(小数点以下3桁)
メンテナンス性を向上させるため、小数点以下の精度を統一することを推奨します。
表情の設定自体は自然な「悲しい」表情を表現できており、適切です。
public/live2d/nike01/expressions/Think2.exp3.json (1)
1-31
: パラメータの意図を文書化することを推奨目の動きのパラメータ(ParamEyeBallX: -0.712、ParamEyeBallY: 0.288)は、「考え事をしている」表情として左上を見上げる自然な動きを表現していますが、これらの値の意図を文書化することで、将来の調整や他の表情作成時の参考になります。
{ "Type": "Live2D Expression", "FadeInTime": 0.75, + "Description": "左上を見上げながら考え込む表情。目の位置は左上(X: -0.712、Y: 0.288)を指定し、口の形は少し開いた状態(MouthForm: -0.635)に設定。", "Parameters": [
表情パラメータの組み合わせは適切で、自然な「考え事をしている」表情を実現できています。
public/live2d/nike01/expressions/Happy2.exp3.json (1)
1-36
: 表情パラメータの整理と文書化を推奨
- パラメータの整理について:
- 関連するパラメータ(左目/右目、笑顔関連など)をグループ化することで可読性が向上します
- 推奨される順序:
- 髪飾り(ParamHairpinChange)
- 目の開閉(ParamEyeLOpen, ParamEyeROpen)
- 目の表情(ParamEyeLSmile, ParamEyeRSmile)
- 口の形状(ParamMouthForm)
- 表情の意図の文書化:
- Happy2とHappyの違いを明確にするためのコメントの追加を推奨します
- 各パラメータ値の選定理由の文書化も検討してください
public/live2d/nike01/expressions/Focus.exp3.json (1)
1-51
: Live2D表情ファイルの管理方針について
- 表情ファイルの一貫性確保:
- すべての表情ファイルで
FadeInTime
の使用を統一- パラメータの命名規則と順序の標準化
- 小数点以下の精度の統一(現在は混在:整数、小数点1桁、小数点3桁)
- 文書化の提案:
- 各表情の意図と使用シーンの説明
- パラメータ値の調整履歴
- 表情間の関係性(例:Happy と Happy2 の違い)
- 検証プロセスの確立:
- 表情切り替え時の自然さの確認
- 極端な値(-1や1)の使用判断基準
- 複数のパラメータ組み合わせによる意図しない表情の防止
kyarasettei.txt (2)
14-20
: 感情表現の定義について改善の余地があります感情状態(neutral、happy、angry、sad、relaxed)の具体的な使い分けの基準や、各感情がLive2Dモデルのどのパラメータに対応するかの説明を追加することを推奨します。
26-44
: 会話例のカバレッジを拡充することを推奨現在の会話例は基本的な質問に対する応答が中心です。以下のようなシナリオも追加することを推奨します:
- エラー時の応答
- 複数の感情を組み合わせた応答
- 長文の入力への対応
public/live2d/nike01/nike01.model3.json (2)
81-120
: 感情表現の区別についての提案異なる感情状態(Neutral、Happy、Relaxed)で同じモーションファイル(Motion1.motion3.json、Motion3.motion3.json)が使用されています。各感情をより明確に区別するために、感情ごとに固有のモーションを設定することを推奨します。
8-64
: 表情バリエーションの使い分けに関するドキュメント化の提案Happy/Happy2やSad/Sad2など、複数のバリエーションが存在する表情があります。これらの使い分けを明確にするため、各バリエーションの用途や違いについてのドキュメントを追加することを推奨します。
.env.example (1)
159-171
: Live2D設定のサンプル値とドキュメントの追加提案感情設定(NEXT_PUBLIC_*_EMOTIONS)やモーショングループの環境変数について、以下の改善を提案します:
- 各変数の期待される形式と値の例を追加
- カンマ区切りリストの具体例の提供
- 設定値の有効範囲の説明
例:
-NEXT_PUBLIC_NEUTRAL_EMOTIONS="" +# Format: comma-separated emotion names +NEXT_PUBLIC_NEUTRAL_EMOTIONS="Neutral,NoSmile"public/live2d/nike01/motions/Motion6.motion3.json (1)
38-64
: パラメータカーブの最適化提案目のまばたきアニメーション(ParamEyeLOpen、ParamEyeROpen)のセグメントが非常に複雑です。維持管理性を向上させるため、以下の最適化を提案します:
- セグメント数の削減
- キーフレームの整理
- 左右の目の同期化による設定の簡素化
これにより、アニメーションの品質を保ちながら、設定の管理が容易になります。
public/live2d/nike01/motions/Motion1.motion3.json (1)
181-190
: 髪の動きの自然さについて
ParamHairAhoge
のセグメントにおいて、以下の問題が見られます:
- 値の変化が急激(-10から10への急な変化)
- 振動が大きすぎる
より自然な動きにするために、以下の修正を提案します:
"Segments": [ 0, 0, 1, 0.144, 0, 0.289, 10, 0.433, 10, 1, 0.578, 10, 0.722, -10, - 0.867, -10, 1, 0.989, -10, 1.111, 4, 1.233, 4 + 0.867, -6, 1, 0.989, -6, 1.111, 2, 1.233, 2public/live2d/nike01/motions/Motion3.motion3.json (1)
153-157
: 呼吸のアニメーションについて
ParamBreath
のパラメータにおいて、呼吸のサイクルが機械的で不自然です。より自然な呼吸の動きにするために、以下の修正を提案します:
- サイクルの長さを不均一にする
- 振幅を徐々に変化させる
- イーズイン・イーズアウトを適用する
"Segments": [ - 0, 0, 1, 0.189, 0, 0.378, 1, 0.567, 1, 1, 0.733, 1, 0.9, 0, 1.067, 0 + 0, 0, 1, 0.2, 0.2, 0.4, 0.8, 0.6, 1, 1, 0.8, 1, 0.9, 0.2, 1.1, 0public/live2d/nike01/motions/Motion2.motion3.json (1)
14-234
: アニメーションカーブの改善提案以下の点について検討をお願いします:
- 急激な動きの変化(特にParamAngleZ)があり、より自然な動きにするため、イージング調整を推奨します
- アイドル状態(PartOpacity)の動きがやや単調です
public/live2d/nike01/motions/Motion5.motion3.json (1)
14-248
: モーション設定の最適化について以下の改善点を提案します:
- 目のパラメータ(ParamEyeLOpen/ParamEyeROpen)の同期性を確認してください
- 体の動き(ParamBodyAngleX/Y/Z)の遷移がやや急激です
- 髪の動き(ParamHairAhoge)をより自然にするため、イージングの調整を推奨します
locales/ja/translation.json (3)
50-50
: システムプロンプトの説明をより具体的に改善できます現在の説明は基本的な情報を提供していますが、より具体的な例を追加することで、ユーザーの理解を深めることができます。
- "CharacterSettingsInfo": "キャラクター設定はシステムプロンプトに設定されます。\n初期プロンプトを参考に、感情タグを指定することでキャラクターの表情やモーションを制御できます。例: [neutral]おはようございます![happy]今日もお疲れ様です!", + "CharacterSettingsInfo": "キャラクター設定はシステムプロンプトに設定されます。\n初期プロンプトを参考に、感情タグを指定することでキャラクターの表情やモーションを制御できます。\n\n使用可能な感情タグ:\n- [neutral] - 通常の表情\n- [happy] - 嬉しい表情\n- [sad] - 悲しい表情\n- [angry] - 怒りの表情\n- [relaxed] - リラックスした表情\n\n例: [neutral]おはようございます![happy]今日もお疲れ様です!",
209-211
: 感情設定の説明をより詳細に感情設定の説明をより具体的にすることで、ユーザーが設定をカスタマイズしやすくなります。
- "EmotionInfo": "感情はカンマ区切りで複数指定できます。複数指定した場合はランダムに選択されます。\n初期値はAITuberKitで用意しているモデルに対応したものです。オリジナルのモデルを使用する場合はご自身のモデルに合わせた値を入力してください。\n会話完了後は「通常」の表情が表示されます。", + "EmotionInfo": "感情はカンマ区切りで複数指定できます。複数指定した場合はランダムに選択されます。\n\n例: happy,happy_02,happy_03\n\n初期値はAITuberKitで用意しているモデルに対応したものです。オリジナルのモデルを使用する場合は、Live2Dモデルのパラメータ名に合わせた値を入力してください。\n\n注意点:\n- 大文字小文字は区別されます\n- スペースは使用できません\n- 会話完了後は「通常」の表情が表示されます",
217-218
: モーショングループ設定の説明を改善モーショングループ設定の説明をより具体的にすることで、ユーザーが設定をカスタマイズしやすくなります。
- "MotionGroupsInfo": "モーショングループは選択したグループからランダムに選択されます。\n表情設定と同じく、ご自身のモデルに合わせて設定してください。\n「アイドル時」は会話完了後に表示されるモーションです。", + "MotionGroupsInfo": "モーショングループは選択したグループからランダムに選択されます。\n\n例: idle_01,idle_02,idle_03\n\n表情設定と同じく、Live2Dモデルのモーショングループ名に合わせて設定してください。\n\n各モーショングループの用途:\n- アイドル時: 会話完了後に表示されるモーション\n- 通常: 通常会話時のモーション\n- 感情別: 各感情に対応するモーション",locales/ko/translation.json (1)
208-210
: 感情設定の説明を日本語版と統一韓国語版の感情設定の説明を日本語版と同じ詳細度に揃えることで、言語間での一貫性を保つことができます。
- "EmotionInfo": "감정은 쉼표로 구분하여 여러 개 지정할 수 있습니다. 여러 감정을 지정한 경우 랜덤으로 선택됩니다.\n초기값은 AITuberKit에서 제공하는 모델에 맞춰 설정되어 있습니다. 원본 모델을 사용하는 경우 자신의 모델에 맞춰 값을 입력해 주세요.\n대화가 완료된 후에는 \"기본\" 감정이 표시됩니다.", + "EmotionInfo": "감정은 쉼표로 구분하여 여러 개 지정할 수 있습니다. 여러 감정을 지정한 경우 랜덤으로 선택됩니다.\n\n예: happy,happy_02,happy_03\n\n초기값은 AITuberKit에서 제공하는 모델에 맞춰 설정되어 있습니다. 원본 모델을 사용하는 경우 Live2D 모델의 파라미터 이름에 맞춰 값을 입력해 주세요.\n\n주의사항:\n- 대소문자를 구분합니다\n- 공백은 사용할 수 없습니다\n- 대화가 완료된 후에는 \"기본\" 감정이 표시됩니다",public/live2d/nike01/nike01.cdi3.json (3)
1-479
: パラメータのグループ化と命名規則についてパラメータの構造は論理的ですが、いくつかの改善点があります:
- パラメータ名の一貫性
- グループ化の最適化
- ドキュメント化の強化
以下の改善を推奨します:
- パラメータ名の接頭辞を統一する(例:
Param
の後のカテゴリを明確に)- 関連するパラメータをサブグループにまとめる
- 各パラメータグループの先頭にコメントを追加
{ "Version": 3, + // Group documentation + // ParamGroup: Basic XYZ movements + // ParamGroup2: Output XYZ movements + // ParamGroup3: Basic expressions + // ParamGroup4: Expression physics + // ParamGroup5: Physics-based movements + // ParamGroup6: Key bindings "Parameters": [
480-511
: パラメータグループの構造化を改善パラメータグループの定義は明確ですが、より詳細な説明を追加することで、モデルの管理が容易になります。
"ParameterGroups": [ { "Id": "ParamGroup", "GroupId": "", - "Name": "XYZ" + "Name": "XYZ", + "Description": "基本的な頭と体の動きを制御するパラメータグループ" },
512-597
: パーツの構造化と命名を改善パーツの定義は基本的な情報を含んでいますが、より詳細な情報を追加することで、モデルの管理と更新が容易になります。
"Parts": [ { "Id": "Part", - "Name": "キャラ" + "Name": "キャラ", + "Category": "Base", + "Description": "キャラクターのベースとなる要素" },locales/en/translation.json (1)
207-224
: Live2D関連の設定が体系的に追加されました感情設定とモーショングループの設定が以下の点で適切に実装されています:
- 基本的な感情(neutral、happy、sad、angry、relaxed)が網羅されています
- 各設定の説明文が明確です
- モーショングループとの連携が考慮されています
提案として、以下の改善を検討してください:
- 感情の組み合わせ例をInfoセクションに追加
- カスタム感情の追加方法の説明を含める
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (5)
package-lock.json
is excluded by!**/package-lock.json
public/live2d/nike01/nike01.8192/texture_00.png
is excluded by!**/*.png
public/scripts/live2d.min.js
is excluded by!**/*.min.js
public/scripts/live2dcubismcore.min.js
is excluded by!**/*.min.js
public/voice_test.wav
is excluded by!**/*.wav
📒 Files selected for processing (48)
.env.example
(1 hunks).eslintrc.json
(1 hunks).gitignore
(1 hunks).vscode/settings.json
(1 hunks)kyarasettei.txt
(1 hunks)locales/en/translation.json
(2 hunks)locales/ja/translation.json
(2 hunks)locales/ko/translation.json
(2 hunks)locales/zh/translation.json
(2 hunks)package.json
(2 hunks)public/live2d/nike01/expressions/Angry.exp3.json
(1 hunks)public/live2d/nike01/expressions/Focus.exp3.json
(1 hunks)public/live2d/nike01/expressions/HairpinChange.exp3.json
(1 hunks)public/live2d/nike01/expressions/Happy.exp3.json
(1 hunks)public/live2d/nike01/expressions/Happy2.exp3.json
(1 hunks)public/live2d/nike01/expressions/Neutral.exp3.json
(1 hunks)public/live2d/nike01/expressions/NoSmile.exp3.json
(1 hunks)public/live2d/nike01/expressions/Sad.exp3.json
(1 hunks)public/live2d/nike01/expressions/Sad2.exp3.json
(1 hunks)public/live2d/nike01/expressions/Sleep.exp3.json
(1 hunks)public/live2d/nike01/expressions/Think.exp3.json
(1 hunks)public/live2d/nike01/expressions/Think2.exp3.json
(1 hunks)public/live2d/nike01/expressions/Troubled.exp3.json
(1 hunks)public/live2d/nike01/expressions/Zitome.exp3.json
(1 hunks)public/live2d/nike01/items_pinned_to_model.json
(1 hunks)public/live2d/nike01/motions/Motion1.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion2.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion3.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion4.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion5.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion6.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion7.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion8.motion3.json
(1 hunks)public/live2d/nike01/motions/Motion9.motion3.json
(1 hunks)public/live2d/nike01/nike01.cdi3.json
(1 hunks)public/live2d/nike01/nike01.model3.json
(1 hunks)public/locales/ja/translation.json
(1 hunks)src/components/Live2DComponent.tsx
(1 hunks)src/components/live2DViewer.tsx
(1 hunks)src/components/settings/based.tsx
(3 hunks)src/components/settings/modelProvider.tsx
(1 hunks)src/features/messages/live2dHandler.ts
(1 hunks)src/features/messages/speakCharacter.ts
(3 hunks)src/features/messages/speakQueue.ts
(3 hunks)src/features/stores/home.ts
(5 hunks)src/features/stores/settings.ts
(6 hunks)src/pages/api/get-live2d-list.ts
(1 hunks)src/pages/index.tsx
(2 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
src/features/messages/live2dHandler.ts
[error] 86-86: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 98-98: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 125-125: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 144-144: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 151-151: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 157-157: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 161-161: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 161-162: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
🔇 Additional comments (56)
public/live2d/nike01/motions/Motion4.motion3.json (2)
1-13
: メタ設定の確認
モーションの基本設定が適切に構成されています:
- 4.37秒の適度な長さ
- 30FPSの標準的なフレームレート
- ループなしの設定は意図的な動作として適切
ただし、以下の点について確認をお願いします:
- モーションの長さ(4.37秒)が他のモーションファイルと一貫性があるか
- 30FPSの設定が他のモーションと統一されているか
180-184
: パーツの不透明度設定の確認
PartArmAの不透明度が常に1に固定されています。これは意図的な設定かどうか確認が必要です。
他のモーションファイルでのPartArmAの不透明度設定との整合性を確認してください。
public/live2d/nike01/motions/Motion9.motion3.json (1)
1-25
: Live2Dのmotion3.json形式との互換性を確認してください
ファイル形式は基本的なLive2Dの仕様に従っていますが、以下の点を確認することを推奨します:
- Version 3の最新の仕様との完全な互換性
- 必須フィールドの欠落がないこと
- 値の範囲が仕様で定められた制限内であること
✅ Verification successful
Let me gather more information about the motion files to verify the Meta fields and Curves structure.
Live2Dのmotion3.jsonファイルの検証が完了しました
すべてのモーションファイルが正しい形式で実装されていることを確認しました:
- すべてのファイルがVersion 3を使用しており、一貫性が保たれています
- 必須のMetaフィールド(Duration、Fps、Loop、など)が適切に設定されています
- Curvesセクションが正しい構造(Target、Id、Segments)を持っています
- TargetタイプはLive2D仕様で定義された
Parameter
とPartOpacity
のみを使用しています
モーションファイルの形式に問題はありません。安全に使用できます。
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Live2Dのモーションファイル形式を検証
# 同じディレクトリ内の他のモーションファイルと構造を比較
fd -e json -e motion3.json . public/live2d/nike01/motions/ --exec jq -r 'keys' {} \; | sort | uniq -c
# Versionフィールドの一貫性を確認
fd -e json -e motion3.json . public/live2d/nike01/motions/ --exec jq -r '.Version' {} \; | sort | uniq -c
Length of output: 301
Script:
#!/bin/bash
# Metaフィールドの構造を確認
fd -e json -e motion3.json . public/live2d/nike01/motions/ --exec jq -r '.Meta | keys' {} \; | sort | uniq -c
# Curvesの構造を確認
fd -e json -e motion3.json . public/live2d/nike01/motions/ --exec jq -r '.Curves[] | keys' {} \; | sort | uniq -c
# Targetとパラメータの種類を確認
fd -e json -e motion3.json . public/live2d/nike01/motions/ --exec jq -r '.Curves[].Target' {} \; | sort | uniq -c
Length of output: 719
src/features/messages/speakQueue.ts (2)
3-4
: インポートの追加は問題ありません。
新たに settingsStore
と Live2DHandler
を取り入れており、後続の処理で役立つ構造です。
65-68
: モデル未ロード時の安全対策
live2d
以外を選択した場合は hs.viewer.model?.playEmotion('neutral')
を呼び出していますが、モデルの未ロード時には何も行われない可能性があります。例外回避のためにもロード状態の判定を入れると安全です。
src/components/Live2DComponent.tsx (6)
21-45
: コンポーネント構造とクリーンアップ処理
modelRef
の破棄や PIXI アプリの destroy
は正しく記述され、メモリリークを防いでいます。後続のイベントリスナー追加やモデル読込ロジックとの整合性も良好です。
63-76
: initApp
の初期化手順
PIXI アプリ生成時に antialias: true
と backgroundAlpha: 0
を設定し、透明背景を活用できる点は Live2D との併用に適しており良い設計です。
77-109
: モデル読み込みとタイムアウト処理
10秒間のタイムアウト、once('error')
イベントのリスナー設定はエラー制御として十分です。ただし、過去のレビューでも指摘のとおり、ユーザー通知やフォールバック処理を行うと更にUXが向上します。
111-164
: ポインタ操作の実装
ドラッグやマウスホイールによるスケーリングといった操作が明確に記載されており、イベント登録と解除も適切です。製品版で想定外のスケール操作を防ぐために、ドラッグによる移動制限などのUIデザインも検討ください。
166-186
: リサイズイベントのデバウンス処理
debounce
による呼び出し間隔の制御とクリーンアップ時の onResize.cancel()
はパフォーマンス面とメモリ管理の両面で適切です。過去のレビューでも提案のあったデバウンスが実装されており良好です。
188-197
: コンポーネントのレンダリング
canvas
要素を全画面表示し、ポインタ操作を生かせる実装になっています。右クリック操作を無効化するなど、想定外のコンテキストメニューを防いでいる点も良いです。
src/features/messages/live2dHandler.ts (5)
5-7
: クラス宣言とプロパティ
idleMotionInterval
を null
で初期化している点は適切です。Node.js の Timeout
型を用いており、DOM と Node.js で型が異なる際には注意が必要ですが、ここでは問題ありません。
🧰 Tools
🪛 Biome (1.9.4)
[error] 5-204: Avoid classes that contain only static members.
Prefer using simple functions instead of classes with only static members.
(lint/complexity/noStaticOnlyClass)
8-17
: speak
メソッドのシグネチャ
引数に audioBuffer
, talk
, isNeedDecode
を受け取り、静的メソッドとして実装されています。引数の型定義が明確で、外部呼び出し側にもわかりやすいです。
18-50
: 感情状態に応じた表情・モーションの設定
複数の感情に対して乱数で表情を選択しています。配列が空の場合、エラーにならないか事前にチェックする仕組みも検討してください。
88-110
: オーディオ再生と Live2D ビューア連動
Audio
オブジェクトのボリュームを最低限にしつつ、Live2D 側にも speak
を呼んで二重再生を回避している点は工夫されています。長時間再生でのメモリ解放を忘れないように留意してください。
🧰 Tools
🪛 Biome (1.9.4)
[error] 98-98: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
141-147
: アイドルモーション停止処理
clearInterval
で確実に停止させ、idleMotionInterval
を null
に戻す実装は妥当です。並列呼び出しのリスクを考慮して、呼び出し元でこのメソッドが多重に実行されないことを確認するとさらに安全です。
🧰 Tools
🪛 Biome (1.9.4)
[error] 144-144: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
src/components/settings/based.tsx (2)
39-63
: モーショングループ設定フィールド
モーションのデフォルト値を一元管理し、UI に入力欄を用意する実装は良好です。それぞれのキーが正しいかどうか、Live2D 側でのマッピングを明確にしておくと混乱を避けられます。
Line range hint 158-371
: モデル種別に応じた UI 分岐と Live2D 設定フォームの統合
modelType
が vrm
か live2d
かで表示を切り替える実装は明確で、ユーザーエクスペリエンスが向上します。Live2D 選択時に Live2DSettingsForm
がすぐ使える点も便利です。今後、モデルが増える場合はラジオボタンやセレクタで管理してもよいでしょう。
src/features/stores/settings.ts (5)
59-59
: ModelProvider
への拡張
既存のインターフェースに Live2D 用プロパティを追加しており、整合性のとれた構造になっています。今後 VRM 専用設定も増える場合は別のインターフェースに切り出すことも検討ください。
116-116
: selectedLive2DPath
プロパティ追加
Live2D モデルのパス管理が settingsStore
に組み込まれたことで、コンポーネント間の共有が容易になっています。デフォルト値の存在を考慮し、モデルが存在しない場合のハンドリングもお忘れなく。
145-146
: SettingsState
への組み込み
ModelType
を含めることで管理対象の設定が一元化され、メンテナンスしやすいです。
389-406
: 部分的永続化設定
persist
設定でユーザーの状況に応じたプロパティのみを保存しており、パフォーマンスとセキュリティに配慮できています。Live2D 関連のプロパティも問題なく永続化されます。
300-317
: 🛠️ Refactor suggestion
環境変数からの配列取得処理
空文字列が入る場合に .filter(Boolean)
などで除外しないと、想定外の配列要素が発生するリスクがあります。
- neutralEmotions: process.env.NEXT_PUBLIC_NEUTRAL_EMOTIONS?.split(',') || [],
+ neutralEmotions:
+ process.env.NEXT_PUBLIC_NEUTRAL_EMOTIONS
+ ?.split(',')
+ .filter(Boolean) || [],
Likely invalid or redundant comment.
src/pages/api/get-live2d-list.ts (1)
9-14
: ディレクトリ未存在時のエラーハンドリングが適切です。
fs.existsSync
でディレクトリが存在しない場合に 404 を返しているので、ユーザーに対して明確なエラー応答を示す点がとても良いです。
src/pages/index.tsx (1)
8-8
: Live2DViewer のインポートは適切です。
プロジェクトが複数のモデルタイプをサポートする方針が確認でき、メンテナンス性が高い構成と見受けられます。
src/features/stores/home.ts (3)
7-7
: pixi-live2d-display-lipsyncpatch
のライブラリの依存関係検証
新規追加されたパッケージが他のバージョンと競合しないか、package.json
に記載されるバージョン範囲を合わせて確認すると、予期せぬ不具合を回避しやすくなります。
17-17
: 型指定が any
(重複コメント)
live2dViewer
プロパティについて、型安全性を高めるためにも可能であれば具体的な型定義を検討してください。
29-34
: 状態管理プロパティの追加は妥当です。
isCubismCoreLoaded
や isLive2dLoaded
を分けて管理することで、各スクリプトの読み込みステータスを判別しやすくなっています。今後、読み込み失敗のロジックを拡張する場合もスムーズに対応可能でしょう。
src/components/live2DViewer.tsx (1)
1-2
: 'use client' の明示
Next.js でクライアントコンポーネントとしての利用を宣言しており、意図が明確でわかりやすい実装です。
src/features/messages/speakCharacter.ts (2)
19-19
: Live2DHandlerのインポートを確認してください
この行でLive2DHandlerをインポートすることで、Live2D関連の音声再生を呼び出しているようです。後続の呼び出しロジックに問題がないか、すべての箇所で正しく利用されているかを確認してください。
242-248
: Live2D向け音声再生処理に注目
modelType
が live2d
の場合に Live2DHandler.speak
を呼び出しています。testVoiceVox
のテスト時にも適切に音声が再生されるか、UIイベントなどで競合が発生しないかを念入りに確認すると良いでしょう。
public/locales/ja/translation.json (1)
1-4
: Live2D用の日本語翻訳キーの追加を確認
"Live2DSettings": "Live2D設定"
が追加されました。新規翻訳キーを増やす際には、他の言語や関連箇所との整合性を保つことをおすすめします。発話やUIでこのキーを使用している部分がある場合は、表示内容が正しく反映されるかご確認ください。
public/live2d/nike01/expressions/HairpinChange.exp3.json (1)
1-10
: 新しい表情データの導入を確認
ParamHairpinChange
を使用した追加表情が定義されています。同名パラメータを利用する他の表情ファイルやモデル設定との整合性に注意し、衝突や冗長設定がないかをご確認ください。また、エディタの自動生成ファイルであればバージョン管理や修正方針を周知すると、保守性が高まります。
.vscode/settings.json (1)
1-7
: フォーマッターの設定を確認してください
Prettierの設定とESLintの設定が競合する可能性があります。以下の点を確認してください:
- プロジェクト全体で一貫したコードスタイルが適用されること
- Live2D関連のファイルに対して適切なフォーマットが行われること
✅ Verification successful
Let me try another search pattern to find configuration files.
Let me check for the actual configuration content of ESLint and Prettier.
VSCode設定は適切に構成されています
ESLintとPrettierの設定は適切に統合されており、競合の心配はありません:
- ESLintは
prettier
プラグインとextends
を使用しており、Prettierと協調して動作します - Prettierの設定(
.prettierrc
)は明確に定義されています - VSCodeの設定で指定された
editor.defaultFormatter
とsource.fixAll.eslint
の組み合わせは、この構成と完全に互換性があります
Live2Dファイルに関しても、.eslintrc
のignorePatterns
でpublic/scripts/*
が除外されているため、問題ありません。
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for conflicting formatting configurations
# Check for Prettier config
echo "Checking for Prettier config..."
fd -t f "prettier" -x echo "Found Prettier config: {}"
# Check for ESLint config
echo "Checking for ESLint config..."
fd -t f "eslint" -x echo "Found ESLint config: {}"
Length of output: 247
Script:
#!/bin/bash
# Search for configuration files with different extensions
echo "Checking for Prettier configs..."
fd -e json -e yaml -e yml -e js -e cjs '.prettier' -x echo "Found: {}"
echo "Checking for ESLint configs..."
fd -e json -e yaml -e yml -e js -e cjs '.eslint' -x echo "Found: {}"
# Check package.json for relevant dependencies and configs
echo "Checking package.json..."
if [ -f "package.json" ]; then
echo "Content of package.json:"
cat package.json
fi
Length of output: 3084
Script:
#!/bin/bash
# Check root directory for config files
echo "Checking for .prettierrc.*"
fd -H -d 1 "^\.prettierrc" -x cat {}
echo -e "\nChecking for .eslintrc.*"
fd -H -d 1 "^\.eslintrc" -x cat {}
# Check if prettier config exists in package.json
echo -e "\nChecking prettier config in package.json"
if [ -f "package.json" ]; then
cat package.json | jq '.prettier'
fi
# Check if eslint config exists in package.json
echo -e "\nChecking eslint config in package.json"
if [ -f "package.json" ]; then
cat package.json | jq '.eslintConfig'
fi
Length of output: 797
public/live2d/nike01/expressions/NoSmile.exp3.json (2)
5-15
: パラメータの値範囲を確認してください
表情パラメータについて以下の点を確認してください:
ParamMouthForm
の値が適切な範囲内(-1)であることParamHairpinChange
の値(1)が想定された動作を実現できること- 両パラメータの
Blend
モードが正しく設定されていること
Live2Dモデルのパラメータ範囲とブレンドモードのドキュメント化を推奨します。
2-4
: フェードイン時間の検証が必要です
FadeInTime
の値(0.75秒)が他の表情設定と一貫していることを確認してください。急激な表情の変化を避けるため、適切な値であることが重要です。
✅ Verification successful
フェードイン時間は一貫性が確認できました
すべての表情設定ファイルでFadeInTime
の値が0.75秒に統一されていることを確認しました。これは適切な設定であり、表情の自然な遷移を実現できます。
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check fade-in time consistency across expression files
echo "Checking fade-in times in expression files..."
fd -e json -p "expressions" | xargs grep -l "FadeInTime" | xargs cat
Length of output: 5933
public/live2d/nike01/expressions/Neutral.exp3.json (1)
1-26
: ニュートラル表情のパラメータ一貫性について
ニュートラル(通常)表情の設定において、以下の点を確認してください:
ParamHairpinChange
が1に設定されていますが、通常状態では0が適切かもしれません- 他の表情設定ファイルとパラメータの一貫性を維持する必要があります
以下のスクリプトで他の表情設定との一貫性を確認できます:
public/live2d/nike01/expressions/Angry.exp3.json (1)
1-26
: 怒り表情のパラメータ調整とテスト推奨
怒り表情の自然さを向上させるため、以下の点を検討してください:
ParamMouthOpenY
が0でParamHeMouth
が1の組み合わせが自然な表情になるか確認ParamAngerBrows
の0.5という中間値は適切ですが、実際の表示で意図した表情になっているか確認が必要
Live2Dビューアでの表示確認が必要です。テスト用のスクリプトを作成しましょうか?また、以下の点も確認することを推奨します:
✅ Verification successful
怒り表情のパラメータ値は適切な範囲内です
パラメータの分析結果から、以下のことが確認できました:
ParamMouthOpenY
:他の表情では0.2~0.3の範囲で使用されており、怒り表情での0は意図的な閉じた口の表現として適切ですParamHeMouth
:他の表情では0~1の範囲で使用されており、怒り表情での1(最大値)は強い感情表現として自然ですParamAngerBrows
:他の表情(Focus: 0.663, Troubled: 0.346)と比較して、怒り表情の0.5は適度な強さを表現しています
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# 他の表情設定との比較を行い、パラメータの範囲を確認
echo "Analyzing parameter ranges across expressions:"
for param in ParamMouthOpenY ParamHeMouth ParamAngerBrows; do
echo "Parameter: $param"
rg -l "$param" public/live2d/nike01/expressions/*.exp3.json | while read -r file; do
echo "File: $file"
jq --arg param "$param" '.Parameters[] | select(.Id == $param) | .Value' "$file"
done
done
Length of output: 7257
public/live2d/nike01/expressions/Sad.exp3.json (1)
1-26
: パラメータの一貫性を確認してください
表情パラメータの設定は適切ですが、他の表情ファイルとの一貫性を確保することが重要です。
FadeInTime
が他の表情と同じ0.75秒に設定されていることを確認ParamHairpinChange
、ParamTroubleBrows
などのパラメータ値が他の表情と矛盾していないことを確認
✅ Verification successful
表情パラメータの一貫性を確認しました
検証の結果、以下の点が確認できました:
FadeInTime
はZitome.exp3.json
、Sleep.exp3.json
、HairpinChange.exp3.json
を除く全ての表情で0.75秒に設定されており、一貫性が保たれています。ParamHairpinChange: 1
は全ての表情ファイルで共通して使用されています。Sad.exp3.json
の表情パラメータは他の表情と矛盾なく設定されています:ParamTroubleBrows: 1
はTroubled.exp3.json
やSad2.exp3.json
と同様の値ですParamHeMouth: 1
とParamMouthOpenY: 0.224
の組み合わせは、悲しい表情として適切な値です
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# 全ての表情ファイルのパラメータ値を確認
fd . "public/live2d/nike01/expressions" -e json -x jq -r '["File:", input_filename], ["FadeInTime:", .FadeInTime], ["Parameters:", (.Parameters | map(.Id + ": " + (.Value | tostring)))]'
Length of output: 3863
public/live2d/nike01/expressions/Troubled.exp3.json (1)
1-26
: 表情パラメータの組み合わせを確認してください
ParamTroubleBrows
とParamAngerBrows
を組み合わせることで意図しない表情になる可能性があります:
ParamTroubleBrows
が1.0に設定されている一方で、ParamAngerBrows
が0.346に設定されています- この組み合わせが意図的なものか確認してください
- 実際のモデルで表示して違和感がないか検証することを推奨します
表情のテストや調整が必要な場合は、お手伝いさせていただきます。
public/live2d/nike01/expressions/Sleep.exp3.json (2)
1-3
: FadeInTimeプロパティの追加が必要です
他の表情設定ファイル(Happy2.exp3.json、Focus.exp3.json)と同様に、自然な表情遷移のためにFadeInTime
プロパティの追加を推奨します。
4-34
: パラメータ値の検証をお願いします
睡眠表現のパラメータ設定について:
- 目を完全に閉じる(-1)のは適切です
- 口の形状(-1)は下向きになっていますが、睡眠時の自然な表情として意図的でしょうか
ParamHairpinChange
の値(1)が他の表情と同じですが、睡眠時の特別な状態を表現する必要はないでしょうか
public/live2d/nike01/expressions/Focus.exp3.json (1)
1-51
: 集中表情の微調整値の検証と文書化
- パラメータ値の精度について:
- 多くのパラメータが小数点3桁までの精密な値を使用しています
- これらの値が意図的に調整されたものか確認をお願いします
ParamEyeLOpen: -0.377
ParamMouthOpenY: 0.308
ParamBodyAngleY: -3.077
- 表情の組み合わせについて:
ParamAngerBrows
(0.663)とParamTroubleBrows
(0.288)の組み合わせが使用されていますが、この組み合わせの意図を文書化することを推奨します- 集中表情としての妥当性の確認をお願いします
public/live2d/nike01/expressions/Think.exp3.json (1)
1-61
: パラメータの構成が適切です
Live2Dの表情設定が論理的に構成されており、自然な「考える」表情を実現できる値が設定されています。
パラメータ値の検証を推奨
以下の値について、Live2Dモデルでの動作確認を推奨します:
- ParamAngleZ: 20.192(頭の傾きが大きすぎないか)
- ParamEyeLOpen/ParamEyeROpen: 左右の目の開き具合の差(自然な表情か)
kyarasettei.txt (1)
1-12
: キャラクター設定が包括的です
基本的な性格設定から言語能力まで、詳細に定義されています。
package.json (2)
49-50
: Live2D関連パッケージのバージョン管理について
以前のレビューで指摘されたpixi.js
とpixi-live2d-display-lipsyncpatch
の依存関係の問題が継続しています。
44-44
: lodashの依存関係の追加について
lodash
の追加は適切ですが、型定義(@types/lodash
)のバージョンが一致していることを確認してください:
- lodash: ^4.17.21
- @types/lodash: ^4.17.13
✅ Verification successful
lodashの依存関係は適切に設定されています
package.json
の確認により、以下が検証できました:
lodash
(^4.17.21) と@types/lodash
(^4.17.13) の両方が適切に設定されていますsrc/components/Live2DComponent.tsx
ではdebounce
関数のみを使用しており、必要最小限のインポートとなっています
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# lodashの使用状況を確認
rg -l "import.*from 'lodash'" --type ts --type js
Length of output: 92
Script:
#!/bin/bash
# Check if @types/lodash is present in package.json
rg "@types/lodash" package.json
# Check the specific lodash imports being used
rg "import.*from 'lodash'" -A 2 src/components/Live2DComponent.tsx
Length of output: 219
public/live2d/nike01/motions/Motion6.motion3.json (1)
3-13
: モーションの滑らかさと継続時間に関する提案
現在のモーション設定について、以下の点を確認・検討することを推奨します:
- 継続時間が1.9秒と短く、アニメーションが唐突に終わる可能性があります
- ループが無効化されているため、連続再生時に不自然になる可能性があります
より自然な動きにするために、以下の対応を検討してください:
- 継続時間の延長
- イーズイン/アウトの追加
- ループの有効化
public/live2d/nike01/motions/Motion7.motion3.json (2)
49-77
: 目のパラメータの同期と自然な動きについて
ParamEyeLOpen
とParamEyeROpen
のパラメータが個別に定義されており、わずかな違いがあります。これにより不自然な目の動きが発生する可能性があります。
以下の改善を提案します:
- 両目のパラメータを同一の値に設定
- まばたきのタイミングにランダム性を持たせる
- 開閉の遷移をよりスムーズにする
131-139
: 🛠️ Refactor suggestion
体の動きが急激すぎます
ParamBodyAngleY
のセグメントにおいて、値の変化が急激です(-4から10への変化)。これにより不自然な動きになる可能性があります。
より自然な動きにするために、以下の修正を提案します:
"Segments": [
0, 0, 1, 0.067, 0, 0.133, 0, 0.2, 0, 1, 0.322, 0, 0.444, -4, 0.567, -4,
- 1, 0.789, -4, 1.011, 10, 1.233, 10
+ 1, 0.789, -4, 1.011, 6, 1.233, 6
Likely invalid or redundant comment.
public/live2d/nike01/motions/Motion3.motion3.json (1)
131-139
: 体の動きが急激すぎます
ParamBodyAngleY
のセグメントにおいて、値の変化が急激です(-4から10への変化)。
より自然な動きにするために、前回のレビューで提案した修正を適用することを推奨します。
public/live2d/nike01/motions/Motion2.motion3.json (1)
1-13
: メタデータの設定が適切です
モーションの基本設定(バージョン、時間、FPS、ループ設定)が正しく構成されています。
locales/zh/translation.json (1)
207-224
: Live2D関連の翻訳が適切に追加されています
感情表現とモーショングループの設定が体系的に整理されており、ユーザーにとって分かりやすい構成になっています。
public/live2d/nike01/motions/Motion5.motion3.json (1)
1-13
: メタデータの設定が適切です
モーションの基本パラメータが正しく設定されています。
locales/en/translation.json (1)
50-50
: キャラクター設定の説明文が追加されました
感情タグを使用したキャラクターの表情とモーション制御の説明が適切に追加されています。例文も分かりやすく記載されています。
src/components/settings/modelProvider.tsx (1)
963-968
: AIサービスに応じた設定説明の表示を改善
条件付きレンダリングが適切に実装されています:
- Difyサービス選択時は専用の説明文を表示
- その他のサービスでは感情タグに関する説明を表示
whitespace-pre-line
クラスで改行を適切に処理
実装は論理的で分かりやすいです。
{ | ||
"Target": "Parameter", | ||
"Id": "ParamBodyAngleX", | ||
"Segments": [ | ||
0, 0, 1, 0.244, 0, 0.489, 0, 0.733, 0, 1, 0.933, 0, 1.133, -7, 1.333, | ||
-7, 1, 1.644, -7, 1.956, 0, 2.267, 0, 0, 4.367, 0 | ||
] | ||
}, | ||
{ | ||
"Target": "Parameter", | ||
"Id": "ParamBodyAngleY", | ||
"Segments": [0, 0, 1, 0.244, 0, 0.489, 0, 0.733, 0, 0, 4.367, 0] | ||
}, | ||
{ | ||
"Target": "Parameter", | ||
"Id": "ParamBodyAngleZ", | ||
"Segments": [ | ||
0, 2, 1, 0.233, 2, 0.467, 0, 0.7, 0, 1, 0.733, 0, 0.767, 0, 0.8, 0, 1, | ||
1, 0, 1.2, -4, 1.4, -4, 1, 1.711, -4, 2.022, 5, 2.333, 5, 1, 2.567, 5, | ||
2.8, 3.64, 3.033, 0, 1, 3.133, -1.56, 3.233, -3, 3.333, -3, 1, 3.467, | ||
-3, 3.6, -2, 3.733, -2, 0, 4.367, -2 | ||
] | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
体の動きに関する注意点
体の動きのパラメータ(ParamBodyAngleX/Y/Z)について:
- X軸とZ軸の動きは設定されていますが、Y軸の動きが最小限(line 137)
- 急激な角度変化(例:line 143-146)により不自然な動きが生じる可能性
以下の修正を推奨します:
- Y軸の動きを追加して、より自然な体の揺れを表現
- Z軸の急激な変化を緩和するためのイージング調整
{ | ||
"Target": "Parameter", | ||
"Id": "ParamHairAhoge", | ||
"Segments": [ | ||
0, 0, 1, 0.3, 0, 0.6, 0, 0.9, -0.012, 1, 1.067, -0.019, 1.233, -6.827, | ||
1.4, -6.827, 1, 1.511, -6.827, 1.622, 7.958, 1.733, 7.958, 1, 1.944, | ||
7.958, 2.156, -7.565, 2.367, -7.565, 1, 2.5, -7.565, 2.633, 9.434, | ||
2.767, 9.434, 1, 2.978, 9.434, 3.189, -8.871, 3.4, -8.871, 1, 3.5, | ||
-8.871, 3.6, 7.588, 3.7, 7.588, 1, 3.789, 7.588, 3.878, -3.904, 3.967, | ||
-3.904, 1, 4.011, -3.904, 4.056, -0.032, 4.1, -0.032, 0, 4.367, -0.032 | ||
] | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
アホ毛のモーション改善提案
アホ毛のパラメータ(ParamHairAhoge)について:
- 動きが急激で機械的な印象(例:line 172-177)
- 値の変化が大きすぎる(-8.871から9.434など)
以下の修正を推奨します:
- より滑らかな動きのためのイージング調整
- 値の範囲を適度に抑制(例:-5から5の範囲内)
{ | ||
"Target": "Parameter", | ||
"Id": "ParamBrowLForm", | ||
"Segments": [ | ||
0, 0, 1, 0.067, 0, 0.133, 0, 0.2, 0, 1, 0.278, 0, 0.356, -0.75, 0.433, | ||
-0.75, 0, 4.167, -0.75 | ||
] | ||
}, | ||
{ | ||
"Target": "Parameter", | ||
"Id": "ParamBrowRForm", | ||
"Segments": [ | ||
0, 0, 1, 0.067, 0, 0.133, 0, 0.2, 0, 1, 0.278, 0, 0.356, -0.87, 0.433, | ||
-0.87, 0, 4.167, -0.87 | ||
] | ||
}, | ||
{ | ||
"Target": "Parameter", | ||
"Id": "ParamMouthForm", | ||
"Segments": [ | ||
0, 1, 1, 0.067, 1, 0.133, 1, 0.2, 1, 1, 0.278, 1, 0.356, -1, 0.433, -1, | ||
0, 4.167, -1 | ||
] | ||
}, | ||
{ | ||
"Target": "Parameter", | ||
"Id": "ParamMouthOpenY", | ||
"Segments": [ | ||
0, 0, 1, 0.067, 0, 0.133, 0, 0.2, 0, 1, 0.278, 0, 0.356, 1, 0.433, 1, 0, | ||
4.167, 1 | ||
] | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
表情の遷移をより自然に
口の形状(ParamMouthForm)と眉の形状(ParamBrowLForm、ParamBrowRForm)の変化が急激です。特に0.356秒付近での変化が顕著です。以下の点について検討してください:
- 遷移時間を延長して滑らかにする
- 中間値を追加してアニメーションを段階的に変化させる
{ | ||
"Target": "Parameter", | ||
"Id": "ParamBodyAngleX", | ||
"Segments": [ | ||
0, 0, 1, 0.067, 0, 0.133, 0, 0.2, 0, 1, 0.444, 0, 0.689, 0, 0.933, 0, 1, | ||
1.211, 0, 1.489, 0, 1.767, 0, 1, 2.056, 0, 2.344, -6, 2.633, -6, 1, | ||
3.033, -6, 3.433, 10, 3.833, 10, 0, 4.167, 10 | ||
] | ||
}, | ||
{ | ||
"Target": "Parameter", | ||
"Id": "ParamBodyAngleY", | ||
"Segments": [0, 0, 1, 0.067, 0, 0.133, 0, 0.2, 0, 0, 4.167, 0] | ||
}, | ||
{ | ||
"Target": "Parameter", | ||
"Id": "ParamBodyAngleZ", | ||
"Segments": [ | ||
0, 0, 1, 0.067, 0, 0.133, 0, 0.2, 0, 1, 0.8, 0, 1.4, -2, 2, -2, 1, | ||
2.456, -2, 2.911, 8.125, 3.367, 8.125, 0, 4.167, 8.125 | ||
] | ||
}, | ||
{ | ||
"Target": "Parameter", | ||
"Id": "ParamBreath", | ||
"Segments": [0, 0, 1, 0.067, 0, 0.133, 0, 0.2, 0, 0, 4.167, 0] | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
体の動きの連携について
体の角度パラメータ(ParamBodyAngleX、ParamBodyAngleY、ParamBodyAngleZ)の動きに以下の課題があります:
- X軸とZ軸の動きが独立しすぎており、不自然な動きになる可能性があります
- Y軸の動きが全くないため、動きが平面的になっています
- 呼吸パラメータ(ParamBreath)が活用されていません
自然な動きを実現するため、これらのパラメータの連携を見直すことを推奨します。
{ | ||
"Target": "Parameter", | ||
"Id": "ParamHairAhoge", | ||
"Segments": [ | ||
0, 0, 1, 0.067, 0, 0.133, 0, 0.2, 0, 1, 0.233, 0, 0.267, -5, 0.3, -5, 1, | ||
0.378, -5, 0.456, 10, 0.533, 10, 1, 0.633, 10, 0.733, 4, 0.833, 4, 0, | ||
4.167, 4 | ||
] | ||
}, | ||
{ | ||
"Target": "PartOpacity", | ||
"Id": "PartArmA", | ||
"Segments": [0, 1, 0, 4.17, 1] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
アホ毛の動きの物理的な自然さについて
アホ毛のパラメータ(ParamHairAhoge)の動きが急激すぎます。特に0.456秒での+15度の変化は不自然です。以下の改善を提案します:
- 慣性の概念を取り入れた、より緩やかな動きの設定
- 最大角度の調整(現在の値では大きすぎる可能性があります)
- より細かいセグメントでの制御による自然な揺れの表現
this.stopIdleMotion() | ||
live2dViewer.motion(motion, undefined, 3) | ||
} | ||
|
||
// 音声再生の完了を待つ | ||
// live2dViewer.speakでは音声完了を検知できないので、Audioオブジェクトを使用して音声再生完了を検知している | ||
// Audioオブジェクトの方も再生すると二重に聞こえてしまうので、再生音量を最低限に設定 | ||
// TODO: もっといい方法があればそれに変更する | ||
await new Promise<void>((resolve) => { | ||
const audio = new Audio(audioUrl) | ||
audio.volume = 0.01 | ||
audio.onended = () => { | ||
resolve() | ||
URL.revokeObjectURL(audioUrl) | ||
} | ||
audio.play() | ||
live2dViewer.speak(audioUrl) | ||
}) | ||
} | ||
|
||
static async resetToIdle() { | ||
// インターバルを停止 | ||
this.stopIdleMotion() | ||
|
||
const hs = homeStore.getState() | ||
const ss = settingsStore.getState() | ||
const live2dViewer = hs.live2dViewer | ||
if (!live2dViewer) return | ||
|
||
const idleMotion = ss.idleMotionGroup || 'Idle' | ||
live2dViewer.motion(idleMotion) | ||
const expression = | ||
ss.neutralEmotions[Math.floor(Math.random() * ss.neutralEmotions.length)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
static メソッド内での this
使用へのLint指摘
static メソッドで this
を用いると可読性やクラス意図が分かりにくくなるため、Live2DHandler.stopIdleMotion()
のようにクラス名を直接呼び出す形へリファクタリングが推奨されています。
- this.stopIdleMotion()
+ Live2DHandler.stopIdleMotion()
Also applies to: 144-144
🧰 Tools
🪛 Biome (1.9.4)
[error] 98-98: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 125-125: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
"SceneName": "", | ||
"SceneGroupName": "", | ||
"SceneModel": "", | ||
"SceneID": "", | ||
"Items": [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
シーン設定が未完成です
シーン関連の設定が空になっています。以下の対応を推奨します:
- 必要なシーン情報の追加
- シーングループの定義
- モデルの関連付け
- シーンIDの生成規則の確立
Live2Dモデルの正常な動作のために、これらの設定を完了する必要があります。
kyarasettei.txt
Outdated
- メッセージに [timestamp] が含まれる場合があります。これはメッセージ時点の時刻を表しているので、その時刻を考慮したうえで回答を生成してください。 | ||
- なお、タイムゾーンはポーランドです。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
タイムゾーン設定の実装が不十分です
コードベースを確認したところ、タイムゾーンの処理は天気情報APIのリクエストでのみ使用されており、メッセージのタイムスタンプ処理において、ポーランドのタイムゾーンを考慮した実装が見当たりません。以下の問題点があります:
- メッセージのタイムスタンプは
Date.now()
を使用しており、これはUTCミリ秒を返すため、ポーランドのタイムゾーンが考慮されていません - タイムスタンプの解釈や表示時にタイムゾーンの変換処理が実装されていません
🔗 Analysis chain
タイムゾーン処理の実装確認が必要
タイムゾーンがポーランドと指定されていますが、システム内でこの設定が正しく反映されているか確認が必要です。
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# タイムゾーン関連の実装を確認
rg -l "timezone|getTime|Date\." --type ts --type js
Length of output: 225
Script:
#!/bin/bash
# タイムゾーン関連の実装をより詳細に確認
rg "timezone|getTime|Date\." --type ts --type js -A 3 src/
Length of output: 3642
Summary by CodeRabbit
新機能
バグ修正
ドキュメント
スタイル
テスト