
В общем, мой каминг‑аут: я человек, не созданный для камеры, но почему‑то всё равно желающий творческого выброса и немного славы.
Именно поэтому я стал вести блог — про работу, хобби и всякое странное, что копится в голове. Ничего не продаю, просто рассказываю о своей практике и наблюдениях.
Изначально я выбрал ТГ и ВК как единственные площадки, где текст ещё хоть как‑то котируется, и почти сразу больно ударился о проблему органического трафика.
Что ж, подумал я, бессмысленно «идти против ветра». Надо смотреть туда, где органики сильно больше и где есть шанс показаться новым людям.
А такие площадки сейчас почти полностью построены на видеоконтенте. По‑другому никак: хочешь попасть в ранжирование алгоритмов — дай им вертикальный видос.
Так передо мной встала инженерная задача:
как стать видеоблогером, если я не умею сидеть перед камерой, не люблю долгий техпроцесс создания видео и в принципе не обладаю свободным временем, чтобы выделять отдельный день на съёмку и монтаж?
Короче, вводные такие, что если влезаешь в этот формат, то с головой.
«А я женатый человек — мне нельзя в Бельдяжки».
Так я пришёл к идее создания своего виртуального аватара — системы, которая бы собирала мне видео из моих текстовых сценариев.
Идею генерации видео через ИИ я сразу отверг. Это крипово, ненадёжно и, как по мне, неуважительно к зрителю и читателю. Нейрослоп плодить не хочется.
Разведка существующих инструментов вроде 3D‑витубер‑аватаров тоже закончилась ничем. Кастомизация персонажа слабая, мимика примитивная, ощущение такое, будто ты выбираешь себе не цифровое лицо, а скин в Роблоксе.
Остался только один вариант — делать всё самому. То есть создать кастомного персонажа, который будет делать всё, что я захочу.
Архитектура проекта получилась примерно такой:
After Effects — финальная сборка, таймлайн и рендер
Photoshop — подготовка графических ассетов персонажа
набор PSD/PNG‑ассетов для рта, глаз, мимики и слайдов
текстовый сценарий с управляющими тегами
аудиодорожка с моим голосом
файл разметки фраз из Audacity
кастомная JSX‑панель для After Effects, которая собирает проект из всего этого
Важное уточнение: под «без ИИ» я имею в виду, что видео, персонаж, речь, мимика и монтаж не генерируются нейросетью. Это обычная графика, ручные ассеты, мой голос и скрипты поверх After Effects.
Небольшое отступление. Помимо набора профнавыков вроде программирования и дизайна, я давно увлекаюсь анимацией и даже успел немного поработать на ТВ в новостном блоке. То есть видеомонтаж мне знаком. И я прекрасно понимаю, насколько долго делается кастомная анимация и почему лучше не трогать её без автоматизации.
Так я решил сделать свой движок лицевой анимации, который из текстового сценария расставляет мимику моего аватара, субтитры и собирает заготовку вертикального видео. А я потом быстро довожу её до ума в мелочах.
Ожидания по времени были простые:
то, что обычно занимало бы рабочий день, должно занимать пару часов.Столько я готов выделять на это хобби.
Больше — уже не хобби, а новая работа без права на отдых.
Я почти сразу решил, что не буду делать вымышленного персонажа. Это же мой блог и мои мысли, поэтому честнее использовать своё настоящее изображение. Робот со своим лицом — это странно, но всё же честнее, чем прятаться за абстрактным маскотом.

Дальше начались тесты, пробы и сама разработка.
Я пошёл путём классической анимации: разделил персонажа на составляющие и начал заменять их под ситуацию. Сначала сделал набор основных положений губ для рта, потом набор глаз, потом появились более сложные штуки вроде случайного моргания.
Основные формы положений рта, которые покрывают почти весь алфавит (самое важное во всей анимации):
Звуки / буквы |
Как выглядит |
пауза, нейтральное лицо |
рот закрыт или почти закрыт |
м, п, б |
губы плотно сомкнуты |
а, я |
рот открыт широко, вертикально |
э, е, и, ы |
рот растянут шире по горизонтали |
о, ё |
округлый рот, среднее открытие |
у, ю |
маленький округлый рот, губы вперёд |
ф, в |
верхние зубы/губа, лёгкое прикусывание нижней губы |
ш, ж, ч, щ |
узкий округлённый рот, почти «шипящий» |
Упрощённо соответствие букв и состояний рта выглядит так:
function mouthForLetter(letter) { letter = String(letter).toLowerCase(); if ("ая".indexOf(letter) !== -1) return "a"; if ("эеиы".indexOf(letter) !== -1) return "ei"; if ("оё".indexOf(letter) !== -1) return "o"; if ("ую".indexOf(letter) !== -1) return "u"; if ("фв".indexOf(letter) !== -1) return "fv"; if ("шжчщ".indexOf(letter) !== -1) return "sh"; if ("мпб".indexOf(letter) !== -1) return "mpb"; return "pause"; }
Это не фонемный анализ и не распознавание речи. Я просто свожу буквы к небольшому набору визуальных состояний рта. Для стилизованного аватара этого оказалось достаточно: зритель видит не идеальную артикуляцию, а правдоподобное совпадение движения рта с произносимой фразой.

И вот появился первый прототип. Показываю его жене. Она внимательно смотрит и говорит, что всё это очень круто и технологично, но сам персонаж крайне кринжовый и будет пугать зрителя. Аватар слишком сильно попал в зловещую долину.
«То есть, это будто бы ты, но ненастоящий», — цитата супруги.

Размышляя над этой проблемой, я пришёл к компромиссу: стилизовать изначально реалистичную фотографию под пиксельное ретро. Чтобы результат больше напоминал персонажа из игры, чем человека. Такому можно простить несовершенство анимации.
Тестовые показы всех удовлетворили. Аватар уже не пугал. А это, согласитесь, важный этап любого творческого проекта: сначала перестать пугать близких.

Виртуальный «я» уже умел шевелить ртом под буквы и показывать базовую мимику. Сначала я вручную помечал начала слов на таймлайне, а анимация строила набор ключевых кадров под каждую букву. Уже нифига себе уровень: по губам аватара можно было читать текст.
Упрощённо логика построения таймлайна выглядит так:
function buildTimeline(ctx, sourceText) { var events = []; var actions = []; var time = 0; var speechIndex = 0; function emitSpeechLetter(letter) { var mouth = mouthForLetter(letter); var frames = framesForLetter(ctx, letter, mouth); events.push({ index: speechIndex, letter: letter, mouth: mouth, time: time, frames: frames }); speechIndex++; time += frames * ctx.FRAME; } for (var i = 0; i < sourceText.length; i++) { var letter = sourceText.charAt(i); if (letter === "[") { // здесь разбираются управляющие теги: // паузы, моргание, мимика, движение, слайды continue; } emitSpeechLetter(letter); } return { events: events, actions: actions, endTime: time }; }
На этом этапе у меня появляется не видео, а внутренний список событий: в какой момент какой рот включить, где поставить паузу, где запомнить действие для глаз, головы, движения или слайда.
Но тут вскрылась проблема. Разметить 10–15 слов — вообще не вопрос. А вот текст для 30-секундного ролика меня вымотал. Всё ещё слишком много ручного труда.
Была попытка привязать ключевые кадры гласных к пикам звуковой дорожки, но в живой речи звуки часто слипаются. Если где‑то в начале проглотишь букву, дальше вся разметка начинает деградировать по нарастающей.
Поэтому через несколько версий я пришёл к более рабочему варианту. В момент записи речи я явно оставлял большие паузы между предложениями. Это делило звук на сегменты‑предложения. Потом программа соотносила предложения звука с предложениями текста, а анализатор пиков уже помогал примерно размечать буквы внутри фразы.

Так получилось, что губы не шевелились в паузах и примерно попадали в звуки слов. Не идеальный лип‑синк, но достаточный для работы. И главное — почти без затрат для оператора. Разметить 10 предложений в звуке — это пара минут.
Разметка Audacity внутри панели читается примерно так:
function readAudacityLabels(ctx) { var file = new File(ctx.AUDACITY_LABELS_PATH); var labels = []; file.open("r"); file.encoding = "UTF-8"; while (!file.eof) { var line = file.readln().replace(/^\uFEFF/, "").trim(); if (line === "" || line.charAt(0) === "#") { continue; } var parts = line.split("\t"); var startTime = parseFloat(parts[0].replace(",", ".")); var endTime = parseFloat(parts[1].replace(",", ".")); var labelText = parts.length >= 3 ? parts.slice(2).join(" ") : ""; if (!isNaN(startTime) && !isNaN(endTime) && endTime > startTime) { labels.push({ start: startTime, end: endTime, text: labelText, duration: endTime - startTime }); } } file.close(); return labels; }
function mapTimeInPhrase(sourceTime, mapItem) { var sourceSpan = mapItem.sourceEndTime - mapItem.sourceStartTime; var targetSpan = mapItem.targetEndTime - mapItem.targetStartTime; if (sourceSpan < 0.001) { return mapItem.targetStartTime; } var ratio = (sourceTime - mapItem.sourceStartTime) / sourceSpan; return mapItem.targetStartTime + targetSpan * ratio; }
Фактически я не распознаю речь. Я беру примерный «синтетический» тайминг фразы, построенный по тексту, и растягиваю или сжимаю его до реальной длительности region label из Audacity. Поэтому фраза попадает в звук, длинные паузы исчезают, а рот не шевелится там, где человек молчит.
Так движок анимации дошёл до следующего уровня: речь аватара начала собираться в анимацию почти без ручной разметки.

А когда у тебя на руках появляется работающий движок, остановиться уже сложно. Он уже мог бы просто заменить диктора в новостях, но мне, конечно, стало мало. Я захотел сделать его не диктором, а настоящим актёром, чтобы он делал в кадре всякое по команде.
Поэтому дальше я сконцентрировался на том, чтобы персонаж понимал команды из текстового сценария. Мимика разрослась, появилась система движения по кадру, а сам сценарий начал управлять аватаром через теги.
Например, кусок сценария теперь выглядит примерно так:
//ФРАЗА-1-начало// [слайд 1 шаблон 1] [пауза 0.3 размышление] Живём в какое-то [моргнуть] особенно безумное время. [пауза 0.4 недовольство] [слайд убрать] //ФРАЗА-1-конец//
Наблюдательный читатель мог заметить, что там есть ещё и теги слайдов. Они тоже предмет моей гордости. Программа сканирует длительность блоков речи и пауз, а потом автоматически расставляет на таймлайне заготовки для слайдов в верхней части видео.
Примеры тегов:
[пауза 0.3 размышление] — вставить паузу и включить мимику размышления [моргнуть] — принудительное моргание [слайд 1 шаблон 1] — создать слайд из шаблона [слайд убрать] — убрать текущий слайд
Чуть кода про работу с тегами (внутри панели теги классифицируются примерно так):
function tagKind(rawTag) { var t = cleanTag(rawTag); if (t.indexOf("морг") !== -1 || t === "blink") { return "blink"; } if (t.indexOf("пауза") !== -1 || t.indexOf("pause") !== -1) { return "pause"; } if (t.indexOf("ирон") !== -1) { return "irony"; } if (t.indexOf("сомнен") !== -1) { return "doubt"; } if (t.indexOf("слева") !== -1 || t.indexOf("left") !== -1) { return "pos_left"; } if (t.indexOf("справа") !== -1 || t.indexOf("right") !== -1) { return "pos_right"; } if (t.indexOf("слайд") !== -1 || t.indexOf("slide") !== -1) { return "slide"; } return "unknown"; }
В реальном коде классификация шире: там есть движение, входы и выходы из кадра, scale‑акценты, разные головы, глаза, слайды и служебные блоки. Но принцип простой: сценарий остаётся читаемым для человека, а панель превращает квадратные скобки в команды для After Effects.
Слайды собираются из тех же событий таймлайна:
function collectSlideSegmentsFromActions(actions, finalEndTime) { var segments = []; var active = null; for (var i = 0; i < actions.length; i++) { var action = actions[i]; var slide = parseSlideAction(action.label); if (!slide) { continue; } if (slide.type === "show") { if (active) { active.endTime = action.time; active.autoClosed = true; segments.push(active); } active = { slideNumber: slide.slideNumber, templateNumber: slide.templateNumber, startTime: action.time, endTime: finalEndTime }; } if (slide.type === "hide" && active) { active.endTime = action.time; segments.push(active); active = null; } } if (active) { segments.push(active); } return segments; }
В результате слайд живёт ровно между двумя событиями таймлайна:
[слайд N шаблон M]и[слайд убрать]. Если закрывающий тег забыт, система не ломает сборку, а закрывает слайд автоматически по следующему событию или по концу ролика.
То есть получается уже настоящий сторителлинг: аватар говорит, слайды сменяются, титры появляются, мимика работает, а я не сижу восемь часов и не двигаю каждый слой руками.

И отдельно After Effects‑специфичная часть: как переключаются ассеты.
Все состояния рта и глаз — это отдельные слои, а панель просто включает нужный слой в нужный момент.
function setHoldAt(ctx, layer, time, value) { var opacity = layer .property("ADBE Transform Group") .property("ADBE Opacity"); opacity.setValueAtTime(time, value); var keyIndex = opacity.nearestKeyIndex(time); if (keyIndex >= 1 && Math.abs(opacity.keyTime(keyIndex) - time) < 0.001) { opacity.setInterpolationTypeAtKey( keyIndex, KeyframeInterpolationType.HOLD, KeyframeInterpolationType.HOLD ); } } function switchGroup(ctx, group, activeKey, time) { for (var key in group) { if (group.hasOwnProperty(key)) { setHoldAt(ctx, group[key], time, key === activeKey ? 100 : 0); } } }
Все состояния рта и глаз — это отдельные слои. В нужный момент панель ставит opacity 100 нужному слою и 0 всем остальным. Интерполяция HOLD нужна, чтобы After Effects не пытался плавно перетекать между состояниями рта. Мне нужен не morphing, а дискретная замена ассета.
Итак, цель удалось достичь: 30-секундный ролик из 10 предложений и 5–6 слайдов теперь собирается примерно за 1–2 часа, а не за день.
Что получилось автоматизировать:
разбор сценария с тегами
расстановку фраз по аудио
переключение ассетов рта
мимику глаз
случайное и принудительное моргание
движение персонажа по кадру
генерацию слайдов
субтитры
сборку начальной композиции в After Effects
Что осталось ручным:
запись голоса
подготовка текста
проверка таймингов
финальная правка слайдов
экспорт
публикация
Правда, чтобы это сделать, пришлось по сути написать кастомный анимационный движок на JS поверх After Effects.
Кто‑то может назвать меня безумным изобретателем, ведь проще было просто сесть перед камерой. Но я «таков и больше никаков».
И да, это настоящий киберпанк — ведь я буквально себя оцифровал.
Теперь мои заметки в новых соцсетях представляет «лучшая версия меня» — в меру пиксельная, насколько возможно, харизматичная, но, надеюсь, всё‑таки душевная, потому что собирается моими руками, моими костылями и моим упрямством, а не случайной ИИ‑генерацией.
Итогом этого эксперимента стали три вертикальных видео, собранных из контента, который я ранее писал в своём ТГ.
Прямые ссылки на ролики не вставляю, чтобы не превращать статью в самопромо. Но при желании их легко найти на YouTube по названию из скринов.
С большой опаской я выложил их на все доступные видеоплощадки:
ВКонтакте
YouTube (раздел Shorts)
Instagram (раздел Reels)
TikTok
Результаты внезапно меня приятно удивили —
суммарный охват превысил 7 тысяч просмотров за 2 недели с нулевых аккаунтов.
Соцсеть |
Выпуск 001 |
Выпуск 002 |
Выпуск 003 |
Итого по соцсети |
Вывод |
ВКонтакте |
10 |
94 |
39 |
143 |
почти не дал просмотров в этом тесте |
YouTube (раздел Shorts) |
1036 |
1117 |
831 |
2984 |
даёт просмотры |
Instagram (раздел Reels) |
384 |
1250 |
1109 |
2743 |
даёт просмотры |
TikTok |
922 |
97 |
240 |
1259 |
сработал нестабильно, но дал просмотры |
Итого за ролик |
2352 |
2558 |
2219 |
||
Суммарный охват: |
7129 просмотров |
||||

И несложный вывод по этому маленькому эксперименту:
вертикальные видеоплощадки действительно могут дать начинающему автору первые тысячи просмотров без рекламного бюджета и без уже собранной аудитории.
Но разброс между площадками оказался большим.
В моём тесте YouTube Shorts и Instagram Reels дали основной объём просмотров, TikTok сработал нестабильно, а VK Клипы почти не взлетели. Выборка маленькая, поэтому это не исследование рынка, а скорее полевой дневник одного самодельного аватара.
Ну а я продолжу свои исследования.
В планах: адаптировать программу под горизонтальный формат, чтобы проверить уже длинный жанр видео.
Спасибо за внимание!
Крайне надеюсь, что этот эксперимент вдохновит кого‑то на создание своего контента.
Комментарии (8)

shovdmi
13.07.2026 09:17А где ссылка на примеры результата? В статье даже нет "подписывайтесь на мой телеграмм канал"

oe_2108 Автор
13.07.2026 09:17я постеснялся в статье такое делать)
но если будут желающие изучить, то вот ссылки:
ютуб, тут будет продолжение видосов в формате из статьи:
https://www.youtube.com/@oe_2108
телега, тут агрегатор вообще всех записей примерно за полгода (личное, работа, наблюдения):
https://t.me/life_2108
тредс, где я больше шучу, чем душню:
https://www.threads.com/@oe_2108

JerryI
13.07.2026 09:17как стать видеоблогером, если я не умею сидеть перед камерой, не люблю долгий техпроцесс создания видео и в принципе не обладаю свободным временем, чтобы выделять отдельный день на съёмку и монтаж?
1. выберете другое хобби
2. Directed by Robert B. Weide
warus
13.07.2026 09:17вали искусно деревья каменным топором неделю, человек бездарно изобретёт бензопилу и потратит на бревно 5 минут.

Zhabrozavr
13.07.2026 09:17А что - креативно, выразительно, нестандартно, а что еще нужно?
Вот что напомнило https://youtu.be/OJWJE0x7T4Q?si=nct393XbkPHLbMoW
Но я лично не замечаю проблем с киногеничностью.
iONHOLM
О У Ю в одну отдельную имхо.
Внешне почти одинаково, внутри отличаются.
oe_2108 Автор
Да, согласен, визуально это близкие формы.
У/Ю и О/Ё у меня разделены не из строгой фонетики, а скорее эмпирически: хотелось, чтобы у стилизованного аватара рот не залипал в одном округлённом состоянии.
Понятно, что основные различия там больше “внутри” артикуляции: язык, положение во рту, сам звук. Но на скринах мне всё же показалось, что разницу можно чуть подчеркнуть.
Благо в системе это просто таблица соответствий, так что такие группы легко объединять/разносить без перестройки пайплайна.
: