ہمارا Rive اینیمیشن پائپ لائن: عربی کرداروں کو زندگی دینا
Amal تمام کرداروں کی اینیمیشنز کے لیے Rive (پہلے Flare) استعمال کرتا ہے — جس میں لپ سنکڈ تقریر، اوتار کی تخصیص، فیڈ بیک ری ایکشنز، اور گیم کردار شامل ہیں۔ ہم نے Lottie یا sprite sheets کے بجائے Rive کو منتخب کیا کیونکہ یہ رن ٹائم اسٹیٹ مشینز، پروگراممیٹک کنٹرول، اور GPU-accelerated رینڈرنگ (60fps) کی سہولت دیتا ہے، اور ہر کردار کے لیے ایک سنگل کمپیکٹ فائل ہوتی ہے۔
اینیمیشن اثاثہ جات کا لائبریری
کور کردار
lip-sync-amal-01.riv
- اہم Amal کردار (پورے جسم اور صرف چہرے کے ویرینٹس)
- ہر منہ کی پوزیشن کے لیے متعدد آرٹ بورڈز (فونیم میپنگ کے لیے)
- اسٹیٹس: بے کار، بولنا، غلطی، جشن، نیند
- فائل سائز: 1.2 MB (sprite sheets کے 50+ MB کے مقابلے میں)avatar.riv
- تخصیص پذیر صارف اوتار (3 آرٹ بورڈز)
1. پورا جسم: سر، جسم، ہاتھ پاؤں کے ساتھ کپڑے
2. صرف سر: ڈیش بورڈ اور والدین ایپ کے لیے
3. تتلی ساتھی: انعامی اینیمیشن
- جزو پر مبنی: سروں کے انداز، بال، آنکھیں، کپڑے، زیورات، رنگ
- فائل سائز: 2.4 MBcoin-01.rivاورcoins-01.riv
- انعامی اینیمیشنز (سنک، جمع کرنا)
- ایک سکے کا سائز: 150 KB
- متعدد سکے: 300 KBcute-monster-final.riv
- فیڈبیک کردار متعدد جذباتی حالتوں کے ساتھ
- حالتیں: خوش (صحیح جواب)، الجھن (غلط جواب)، سوچنا (عملدرآمد)، جشن منانا (سلسلہ)
- فائل سائز: 1.8 MB
اینڈرائڈ مخصوص اصلاحات
- مخصوص NDK بلڈ (Rive NDK-r28) 16KB پیج الائنمنٹ کے لیے
- بائنری سائز 8% کم
- اینڈرائڈ 12+ میں میموری مینجمنٹ کے لئے مطابقت
لپ سنک پائپ لائن (تکنیکی وضاحت)
مرحلہ 1: TTS آڈیو جنریشن اور تقریری نشانوں کا استخراج
# src/services/tts_client.py
from google.cloud import texttospeech
def generate_speech_with_marks(text: str, language: str = 'ar-SA'):
client = texttospeech.TextToSpeechClient()
synthesis_input = texttospeech.SynthesisInput(text=text)
voice = texttospeech.VoiceSelectionParams(
language_code=language,
name='ar-SA-Neural2-A' # WaveNet voice
)
audio_config = texttospeech.AudioConfig(
audio_encoding=texttospeech.AudioEncoding.MP3,
effects_profile_id=['small-bluetooth-speaker-class-device'] # Child's speaker
)
# Request speech marks (phoneme timing)
request = texttospeech.SynthesizeSpeechRequest(
input=synthesis_input,
voice=voice,
audio_config=audio_config,
enable_text_to_speech_as_cloud_service=True
)
response = client.synthesize_speech(request=request)
# Response includes:
# - audio_content: MP3 bytes
# - timepoints: [{character, byte_pos, time_ms}, ...]
return {
'audio': response.audio_content,
'speech_marks': response.timepoints # Phoneme-level timestamps
}
مرحلہ 2: Rive منہ کی حالتوں میں فونیم میپ کرنا
lip_sync_avatar.json عربی فونیمز کو منہ کی پوزیشن سے جوڑتا ہے:
{
"phoneme_map": {
"ا": { "rive_state": "mouth_a_open", "duration_ms": 200 },
"ب": { "rive_state": "mouth_lips_closed", "duration_ms": 150 },
"ع": { "rive_state": "mouth_pharyngeal", "duration_ms": 250 },
"ق": { "rive_state": "mouth_uvular", "duration_ms": 180 },
...
},
"mouth_positions": [
{ "id": "mouth_a_open", "blend_values": { "jaw_open": 0.8, "lips_rounded": 0.2 } },
{ "id": "mouth_lips_closed", "blend_values": { "jaw_open": 0.1, "lips_rounded": 0.9 } },
...
]
}
مرحلہ 3: LipSyncController پلے بیک کو کنٹرول کرتا ہے
// lib/src/modules/animations/controllers/lip_sync_controller.dart
class LipSyncController extends GetxController {
late Rive riveCharacter;
late AudioPlayer audioPlayer;
late LipSyncMapper mapper;
void playWithLipSync(String text, String audioPath) {
// مرحلہ 1: Rive کردار لوڈ کریں
riveCharacter.loadRiveFile('lip-sync-amal-01.riv');
// مرحلہ 2: TTS سے تقریری نشان لوڈ کریں
mapper = LipSyncMapper.fromJson(loadJsonAsset('lip_sync_avatar.json'));
// مرحلہ 3: آڈیو چلائیں اور منہ کی حرکت کریں
audioPlayer.play(AudioSource.file(audioPath));
// مرحلہ 4: ہر آڈیو فریم پر منہ کی حالت اپڈیٹ کریں
audioPlayer.onPositionChanged.listen((Duration position) {
String phoneme = mapper.phonemeAtTime(position.inMilliseconds);
String riveState = mapper.riveStateForPhoneme(phoneme);
riveCharacter.setStateInput('mouth_state', riveState);
});
}
}
مرحلہ 4: RiveCharacterController مکمل کردار کی اینیمیشن چلاتا ہے
// مکمل کردار کے اینیمیشن اسٹیٹس کو منظم کرتا ہے (صرف منہ نہیں)
class RiveCharacterController extends GetxController {
States: idle → prepare → speaking → idle → error/celebration
void startExercise() {
// کردار کی تبدیلیاں: بے کار → تیار (سنتے کے لئے تیار)
character.setStateInput('state_machine', 'prepare');
}
void childSpeaks(String recognizedText, double accuracy) {
character.setStateInput('state_machine', 'speaking');
lipSyncController.playFeedback(recognizedText);
}
void onFeedbackComplete(bool wasCorrect) {
if (wasCorrect) {
character.setStateInput('state_machine', 'celebrate');
playRewardAnimation();
} else {
character.setStateInput('state_machine', 'error');
playEncouragingPhrase();
}
}
}
اوتار تخصیص کا نظام
اجزا پر مبنی ساخت
بچے اپنے اوتار کو حصوں سے اپنی مرضی کے مطابق بناتے ہیں:
{
"avatar_customization": {
"head_shapes": [
{ "id": "round", "rive_element": "head_round" },
{ "id": "oval", "rive_element": "head_oval" },
{ "id": "square", "rive_element": "head_square" }
],
"hair_styles": [
{ "id": "ponytail", "rive_element": "hair_ponytail" },
{ "id": "braids", "rive_element": "hair_braids" },
{ "id": "straight", "rive_element": "hair_straight" }
],
"colors": {
"skin_tone": ["light", "medium", "dark"],
"hair_color": ["black", "brown", "blonde", "red"],
"shirt_color": ["blue", "pink", "green", "yellow", "purple"],
"accent_color": ["red", "orange", "green", "blue"]
}
}
}
Rive پر مبنی ناموں کا میپنگ (avatar_customization_rive_names.dart)
const avatarRiveNames = {
'head_round': 'Head_Round',
'head_oval': 'Head_Oval',
'hair_ponytail': 'Hair_Ponytail',
'shirt_blue': 'Shirt_Blue',
'shirt_pink': 'Shirt_Pink',
// ... 50+ element mappings
};
جب بچہ "گول سر + نیلا قمیص" منتخب کرتا ہے، ایپ یہ کرتی ہے:
1. Rive عنصر Head_Round فعال کرے
2. Rive عنصر Shirt_Blue فعال کرے
3. تمام دوسرے سر کے انداز اور قمیص کے رنگ غیر فعال کیے جائیں
4. بچہ کا ذاتی اوتار ایپ میں ہر جگہ ظاہر ہو جائے
Rive کیوں منتخب کیا گیا؟
| خصوصیت | Rive | Lottie | Sprite Sheets | ویڈیو |
|---|---|---|---|---|
| اسٹیٹ مشینز | ✓ | ✗ | ✗ | ✗ |
| رن ٹائم کنٹرول | ✓ (مکمل) | جزوی | دستی | ✗ (غیر متحرک) |
| فائل سائز | 1-2 MB | 2-3 MB | 50+ MB | 100+ MB |
| کارکردگی | 60fps GPU | 30fps CPU | 60fps GPU | متغیر |
| انٹرایکٹوٹی | ✓ مکمل | ✓ جزوی | ✓ مکمل | ✗ کوئی نہیں |
| سیکھنے کا منحنی | درمیانہ | آسان | آسان | آسان |
| مینٹیننس | ایک .riv فائل | ایک JSON | سینکڑوں تصاویر | ایک ویڈیو |
Rive جیتتا ہے کیونکہ ہمیں پروگراممیٹک کنٹرول، اسٹیٹ مشینز، اور موبائل ایپ کے لیے کمپیکٹ فائل کی ضرورت ہے۔
کارکردگی کی بہتری
- کردار پیشگی لوڈ کریں: اپلیکیشن کے شروع میں .riv فائلیں لوڈ کریں، ہر مشق میں نہیں
- GPU رینڈرنگ: Rive دستیاب GPU استعمال کرتا ہے، پرانے آلات میں CPU fallback ہوتا ہے
- میموری پولنگ: مختلف سکرینز میں Rive کنٹرولرز دوبارہ استعمال کریں تاکہ garbage collection کے وقفے نہ ہوں
- کمپریشن: Rive فائلیں پہلے سے کمپریسڈ ہیں، اضافی اصلاح کی ضرورت نہیں
نتیجہ: Snapdragon 662+ (2019 کے درمیانے فونز) پر 60fps اینیمیشنز
عمومی سوالات
س: کیا میں Adobe Animate سے Rive میں اینیمیشنس براہ راست برآمد کر سکتا ہوں؟
ج: براہ راست نہیں۔ ہم Rive کے نیٹو ایڈیٹر (rive.app) استعمال کرتے ہیں۔ اینیمیٹرز Rive میں ڈیزائن کرتے ہیں، نہ کہ Animate یا After Effects۔ ورک فلو: کردار Rive میں بنائیں → .riv کے طور پر برآمد کریں → Flutter ایپ میں شامل کریں۔
س: جسمانی اقسام یا معذوریوں کو کیسے سنبھالتے ہیں؟
ج: اوتار تخصیص میں جسم کے اقسام (دبلا پتلا، کھیلوں کا جسم، گول) اور لوازمات (چشمے، سماعت معاون)، شامل ہیں تاکہ ہر بچہ نمائندگی دیکھ سکے۔
س: اگر بچہ اپنے اوتار کو پسند نہ کرے تو؟
ج: وہ کسی بھی وقت تخصیص کرسکتے ہیں۔ ایپ کسی قسم کا ظاہری اختیار زبردستی نہیں کرتی — بچوں کو مکمل تخلیقی آزادی حاصل ہے۔



