রাইভ এনিমেশন পদ্ধতি: আরবি চরিত্রকে জীবন্ত তৈরি করা
5 মিনিটের পাঠMohammad Shaker

রাইভ এনিমেশন পদ্ধতি: আরবি চরিত্রকে জীবন্ত তৈরি করা

Amal অ্যাপের চরিত্র এনিমেশনের জন্য রাইভ ব্যবহার করে, যা লিপ-সিঙ্ক, অবতার কাস্টমাইজেশন এবং গেম ক্যারেক্টার সহজ করে তোলে।

Engineering

দ্রুত উত্তর

Amal অ্যাপের চরিত্র এনিমেশনের জন্য রাইভ ব্যবহার করে, যা লিপ-সিঙ্ক, অবতার কাস্টমাইজেশন এবং গেম ক্যারেক্টার সহজ করে তোলে।

আমাদের রাইভ এনিমেশন পদ্ধতি: আরবি চরিত্রকে জীবন্ত করা

Amal অ্যাপের সমস্ত চরিত্র এনিমেশনের জন্য Rive (আগে Flare) ব্যবহার করা হয় — এর মধ্যে লিপ-সিঙ্কড স্পিচ, অবতার কাস্টমাইজেশন, ফিডব্যাক রিয়্যাকশন এবং গেম চরিত্র অন্তর্ভুক্ত। আমরা Lottie বা স্প্রাইট শীটের পরিবর্তে Rive বেছে নিয়েছি কারণ এটি রানটাইম স্টেট মেশিন, প্রোগ্রামেটিক ম্যানিপুলেশন, এবং ৬০fps-এ GPU-অ্যাক্সেলেটেড রেন্ডারিং সমর্থন করে, এবং প্রতিটি চরিত্রের জন্য একটি কমপ্যাক্ট ফাইল থাকে।

অ্যানিমেশন অ্যাসেট লাইব্রেরি

মুখ্য চরিত্রগুলি

  • lip-sync-amal-01.riv
    • মূল Amal চরিত্র (পূর্ণদেহ ও মুখমাত্র ভ্যারিয়েন্ট)
    • মুখের অবস্থানের জন্য একাধিক আর্টবোর্ড (ফোনিম ম্যাপিংয়ের জন্য)
    • স্টেট: idle, speaking, error, celebration, sleeping
    • ফাইল সাইজ: ১.২ এমবি (স্প্রাইট শীটের জন্য ৫০+ এমবির বিপরীতে)
  • avatar.riv
    • কাস্টমাইজযোগ্য ব্যবহারকারীর অবতার (৩টি আর্টবোর্ড)
      1. পূর্ণদেহ: মাথা, শরীর, লিম্বস সহ পোশাক
      2. শুধুমাত্র মাথা: ড্যাশবোর্ড এবং প্যারেন্ট অ্যাপের জন্য
      3. বাটারফ্লাই সঙ্গী: পুরস্কার এনিমেশন
    • কম্পোনেন্ট ভিত্তিক: মাথার আকৃতির, চুল, চোখ, কাপড়, আনুষাঙ্গিক, রং
    • ফাইল সাইজ: ২.৪ এমবি
  • coin-01.riv এবং coins-01.riv
    • পুরস্কার এনিমেশনস (কয়েন ভাসানো, সংগ্রহ)
    • একক কয়েন: ১৫০ কেবি
    • একাধিক কয়েন: ৩০০ কেবি
  • cute-monster-final.riv
    • বিভিন্ন আবেগের স্টেট সহ ফিডব্যাক চরিত্র
    • স্টেট: খুশি (সঠিক উত্তর), বিভ্রান্ত (ভুল), চিন্তা করছে (প্রক্রিয়াধীন), উদযাপন করছে (স্ট্রিক)
    • ফাইল সাইজ: ১.৮ এমবি

অ্যান্ড্রয়েড-নির্দিষ্ট অপ্টিমাইজেশন

  • কাস্টম NDK বিল্ড (Rive NDK-r28) ১৬ কেবি পেজ অ্যালাইনমেন্ট মেনে চলার জন্য
  • স্ট্যান্ডার্ড বিল্ডের তুলনায় বাইনারি সাইজ ৮% কমায়
  • অ্যান্ড্রয়েড ১২+ এর অ্যাগ্রেসিভ মেমোরি ম্যানেজমেন্টের সাথে সামঞ্জস্য নিশ্চিত করে

লিপ-সিঙ্ক পদ্ধতি (প্রযুক্তিগত বিশ্লেষণ)

ধাপ ১: 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']  # বাচ্চাদের স্পিকার
    )
    
    # স্পিচ মার্কস (ফোনিম টাইমিং) অনুরোধ
    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)
    
    # রেসপন্সে থাকে:
    # - audio_content: MP3 বাইট
    # - timepoints: [{character, byte_pos, time_ms}, ...]
    
    return {
        'audio': response.audio_content,
        'speech_marks': response.timepoints  # ফোনিম-লেভেল টাইমস্ট্যাম্প
    }

ধাপ ২: ফোনিমকে Rive মুখের স্টেটের সঙ্গে ম্যাপিং

{
  "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 } },
    ...
  ]
}

ধাপ ৩: 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) {
    // ধাপ ১: Rive চরিত্র লোড
    riveCharacter.loadRiveFile('lip-sync-amal-01.riv');
    
    // ধাপ ২: TTS আউটপুট থেকে স্পিচ মার্কস লোড
    mapper = LipSyncMapper.fromJson(loadJsonAsset('lip_sync_avatar.json'));
    
    // ধাপ ৩: অডিও প্লে করা এবং মুখের এনিমেশন চালানো
    audioPlayer.play(AudioSource.file(audioPath));
    
    // ধাপ ৪: প্রতিটি অডিও ফ্রেমে মুখের অবস্থান আপডেট
    audioPlayer.onPositionChanged.listen((Duration position) {
      String phoneme = mapper.phonemeAtTime(position.inMilliseconds);
      String riveState = mapper.riveStateForPhoneme(phoneme);
      
      riveCharacter.setStateInput('mouth_state', riveState);
    });
  }
}

ধাপ ৪: RiveCharacterController জীবনচক্র নিয়ন্ত্রণ করে

// শুধুমাত্র মুখ নয়, সম্পূর্ণ চরিত্র এনিমেশন নিয়ন্ত্রণ করে
class RiveCharacterController extends GetxController {
  States: idle → prepare → speaking → idle → error/celebration
  
  void startExercise() {
    // idle থেকে prepare রূপান্তর (শ্রবণ প্রস্তুত)
    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 Named Elements Mapping (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',
  // ... ৫০+ উপাদান ম্যাপিং
};

যখন শিশু "রাউন্ড হেড + ব্লু শার্ট" নির্বাচন করে, অ্যাপটি:

  1. Rive উপাদান Head_Round সক্রিয় করে
  2. Rive উপাদান Shirt_Blue সক্রিয় করে
  3. সব অন্য মাথার আকৃতি ও শার্ট রং নিষ্ক্রিয় করে
  4. শিশুর ব্যক্তিগত অবতার সম্পূর্ণ অ্যাপে প্রদর্শিত হয়

কেন Rive অন্যদের থেকে এগিয়ে?

বৈশিষ্ট্যRiveLottieস্প্রাইট শীটভিডিও
স্টেট মেশিন
রানটাইম নিয়ন্ত্রণ✓ (পূর্ণ)আংশিকম্যানুয়াল✗ (নিষ্ক্রিয়)
ফাইল সাইজ১-২ এমবি২-৩ এমবি৫০+ এমবি১০০+ এমবি
পারফরম্যান্স৬০fps GPU৩০fps CPU৬০fps GPUপরিবর্তনশীল
ইন্টারঅ্যাক্টিভিটি✓ পূর্ণ✓ আংশিক✓ পূর্ণ✗ নেই
শিখতে সহজমধ্যমসহজসহজসহজ
রক্ষণাবেক্ষণএকটি .riv ফাইলএকটি JSONশতাধিক ছবিএকটি ভিডিও

Rive জিতে যায় কারণ আমরা প্রোগ্রামেটিক নিয়ন্ত্রণ, স্টেট মেশিন এবং মোবাইল অ্যাপের জন্য কমপ্যাক্ট ফাইল দরকার।

পারফরম্যান্স অপ্টিমাইজেশন

  • চরিত্র প্রিলোড: পর্ব অনুযায়ী নয়, অ্যাপ চালু হওয়ার সময় .riv ফাইল লোড করা হয়
  • GPU রেন্ডারিং: Rive স্বয়ংক্রিয়ভাবে GPU ব্যবহার করে, পুরানো ডিভাইসে CPU ব্যাকআপ থাকে
  • মেমরি পুলিং: স্ক্রীনের মধ্য দিয়ে Rive কন্ট্রোলার রিইউজ করা হয়, গারবেজ কালেকশন রোধ করতে
  • কমপ্রেশন: Rive ফাইলই কমপ্রেস করা থাকে, অতিরিক্ত অপ্টিমাইজ প্রয়োজন হয় না

ফলাফল: Snapdragon 662+ ডিভাইসে ৬০fps এনিমেশন।

প্রশ্নোত্তর

Q: Adobe Animate থেকে Rive-তে কি সরাসরি এনিমেশন এক্সপোর্ট করা যায়?
A: সরাসরি নয়। আমরা Rive-র নিজস্ব এডিটর (rive.app) ব্যবহার করি। এনিমেটররা Animate বা After Effects নয়, Rive-তে ডিজাইন করেন। ওয়ার্কফ্লো: Rive-তে চরিত্র ডিজাইন → .riv হিসাবে এক্সপোর্ট → Flutter অ্যাপে ইন্টিগ্রেট।

Q: ভিন্ন শরীরের ধরন বা প্রতিবন্ধকতা কিভাবে হ্যান্ডেল করেন?
A: অবতার কাস্টমাইজেশনে শরীরের ধরন (স্লিম, অ্যাথলেটিক, গোলাকার) ও আনুষাঙ্গিক (চশমা, হিয়ারিং এইড, মোবিলিটি এইড) অন্তর্ভুক্ত, যাতে সবাই প্রতিনিধিত্ব পায়।

Q: যদি শিশু তাদের অবতার পছন্দ না করে?
A: তারা যেকোন সময় কাস্টমাইজ করতে পারে। অ্যাপ কোনো নির্দিষ্ট লুক চাপিয়ে দেয় না — শিশুদের সম্পূর্ণ সৃষ্টিশীল নিয়ন্ত্রণ রয়েছে।

শেয়ারTwitterLinkedInWhatsApp

সম্পর্কিত নিবন্ধ