Легке створення синхронізації руху губ за допомогою чистого CSS

Коли ми говоримо щось, ми маємо спосіб це виразити, і тут з'являється термін, який ми називаємо фонемою.

Фонема — це найменша одиниця звуку в мові, яка може відрізняти одне слово від іншого. Наприклад, зміна першого звуку в слові "pat" на звук із "bat" змінює значення слова, оскільки "p" і "b" представляють різні фонеми. Фонеми не обов'язково пов'язані з літерами; це абстрактні звуки, які складають будівельні блоки мови.

В англійській мові це зводиться до кількох категорій виразів обличчя, які ми робимо, і це є основною логікою lipsync.js.

const lipSyncTypes = [  
 "aei", "bmp", "cdgknstxyz", "chjsh",  
 "ee", "fv", "l", "o", "qw", "r", "th", "u"  
];

Для довідки:

pic

Типи голосів

Знаючи це, постає дизайнерське завдання: як це зробити? Існує безліч підходів, і жоден з них не є неправильним у фронтенд-розробці. Можна анімувати шляхи SVG або використовувати комбінацію SVG та HTML елементів, але в цьому випадку ми використовували чистий CSS.

Отже, lipsync не має залежностей і використовує властивості CSS @layer для накладання одного шару на інший — просто, правда? Ну, так, кілька сотень рядків CSS, і ви готові.

Можливо, це не так просто, але все ж таки базово, і можна зробити це лише через анімацію властивості border-radius.

Властивість CSS @layer і цей плейграунд для border-radius допомогли мені в цьому, тож обов'язково перевірте їх. Також усі межі мають бути записані в однаковому форматі, інакше вони не будуть анімуватися.

border-radius: 100% 100% 100% 100% / 100% 100% 100% 100%;

Знаючи це, lipsync використовує атрибути даних data-letters, що дозволяє динамічно анімувати їх, коли ці атрибути змінюються.

[data-letters="aei"] {  
 @layer mouth {  
 &.mouth {  
 position: relative;  
 background-color: #b63c2c;  
 overflow: hidden;  
 inline-size: 80px;  
 block-size: 40px;  
 border-radius: 45% 55% 50% 50% / 0% 0% 100% 100%;  
 transition: border-radius 0.3s ease;  
 }  
 }  

 @layer tongue {  
 .tongue {  
 position: absolute;  
 inset-block-end: -5px;  
 inline-size: 30px;  
 block-size: 25px;  
 background-color: #ef7d4a;  
 border-radius: 51% 49% 54% 46% / 34% 39% 61% 66%;  
 transition: border-radius 0.3s ease;  

 &.left-part {  
 inset-inline-start: 20%;  
 }  

 &.right-part {  
 inset-inline-end: 20%;  
 }  
 }  
 }  

 @layer teeth {  
 .teeth {  
 position: absolute;  
 inline-size: 70px;  
 block-size: 10px;  
 background-color: #fffffd;  
 inset-inline-start: 5px;  

 &.upper-part {  
 inset-block-start: -2px;  
 border-radius: 0 0 80px 80px;  
 }  

 &.lower-part {  
 inset-block-end: 0;  
 }  
 }  
 }  
}

Більше того, можна використовувати інтерфейс SpeechSynthesis з Web Speech API, щоб використовувати lipsync.js і змусити аватарів говорити на основі слів і фонем.

function speakText() {  
 const text = document.getElementById("text-to-speak").textContent;  
 const utterance = new SpeechSynthesisUtterance(text);  

 const voices = window.speechSynthesis.getVoices();  
 const englishVoice = voices.find(voice =>  
 voice.lang === "en-GB"  
 );  

 if (englishVoice) {  
 utterance.voice = englishVoice;  
 } else {  
 console.warn("English (UK) voice not found, using default voice.");  
 }  

 const words = text.split(/\s+/);  
 let wordIndex = 0;  

 utterance.onboundary = (event) => {  
 if (event.name === 'word' && wordIndex < words.length) {  
 console.log(words[wordIndex]); // add logic here  
 wordIndex++;  
 }  
 };  

 window.speechSynthesis.speak(utterance);  
 }

З цього моменту можна зробити конструкцію switch case, щоб вирішувати, яку анімацію запускати, замість того, щоб просто запускати їх випадковим чином, що зробить приклад більш практичним.
Анімацію можна запускати, змінюючи атрибути, ось так:

const mouth = document.querySelector(".mouth");  
// використовує змінну lipSyncTypes, визначену вище  
setInterval(() => {  
 mouth.setAttribute("data-letters", lipSyncTypes[~~(Math.random() * 12)]);  
}, 500);

Перевірити все це можна, погравшись із цим Codepen.

Я створив lipSync.js, оскільки відчував, що багато поточних прикладів для синхронізації губ базуються на THREE.js та Azure API, що вимагало деякого рідного рішення.

pic

Живий демонстраційний показ LipSync

Якщо вам сподобалася ця робота, обов'язково загляньте в мій репозиторій на Github (не забудьте поставити зірочку ⭐️!) і буду вдячний за будь-які відгуки чи пропозиції! Також вітаються Pull Requests.

Посилання на репозиторій: https://github.com/yashrajbharti/LipSync.js

Сподіваюся, вам сподобалося читати.

Перекладено з: LipSyncing Made Dead Simple using Pure CSS

Leave a Reply

Your email address will not be published. Required fields are marked *