Я frontend‑разработчик, мой основной стек — Vue. До этой истории я не писал на Swift и практически не работал с Xcode. Тем не менее за два дня у меня появилось нативное приложение для macOS: прямой эфир с PoE‑камеры, непрерывная перемотка архива с её карты памяти, календарь, экспорт роликов, скриншоты и локальное распознавание движения людей и машин.

Приложение называется MiniCam. Его исходный код открыт на GitHub, а готовую universal‑сборку для Intel и Apple Silicon можно скачать в разделе Releases.

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

Интерфейс главного экрана
Интерфейс главного экрана

Всё началось с тормозящего веб‑интерфейса

Я купил PoE‑камеру Hikvision и сначала использовал её встроенный веб‑интерфейс. Картинка была, запись на microSD тоже была, но прямой эфир заметно отставал. Для камеры наблюдения это особенно неприятно: смотришь на реальное движение, а в окне браузера оно происходит через несколько секунд.

Я открыл тот же RTSP‑поток в VLC — и задержка исчезла. Значит, проблема была не в камере и не в сети, а в способе воспроизведения в браузере.

С прямым эфиром VLC справлялся отлично, но мне нужна была ещё история. Не набор отдельных файлов, которые надо открывать по одному, а привычный сценарий как у YouTube: я смотрю эфир, тяну временную шкалу назад, оказываюсь в архиве, перематываю вперёд и возвращаюсь к текущему моменту.

Готовые клиенты либо выглядели тяжёлыми, либо требовали сервер, облако или подписку, либо показывали архив отдельными роликами. Я попробовал несколько вариантов, но ни один не давал одновременно скорость VLC и нужную работу с историей.

В какой‑то момент возникла опасная для свободного времени мысль: «А если написать своё приложение?»

Почему именно нативное приложение

Первой альтернативой был Electron и привычный мне веб‑стек. Интерфейс на Vue я сделал бы быстрее, но RTSP нельзя просто передать в HTML‑тег <video>. Всё равно понадобился бы VLC, FFmpeg или отдельный медиапроцесс, а между ним и браузерным интерфейсом появился бы ещё один слой.

Кроме того, приложение должно было работать не только на Apple Silicon, но и на Intel Mac 2017 года с macOS Monterey. Electron добавил бы заметную нагрузку по памяти и процессору. Поэтому мы выбрали SwiftUI и нативное приложение, а воспроизведение поручили VLCKit — тому же семейству технологий, которое лежит в основе VLC.

«Мы» в данном случае — это я и Codex, работавший прямо с локальным проектом: он мог читать и менять файлы, запускать сборку, тесты и диагностические команды, а также работать с Git.

До начала работы я попросил сначала описать README проекта, требования, цели и ограничения. Это оказалось одним из самых полезных решений. Мы заранее зафиксировали:

  • Одна Hikvision‑совместимая камера в локальной сети

  • Прямой эфир с минимальной задержкой

  • Архив остаётся на microSD камеры, отдельный сервер не нужен

  • Единая временная шкала эфира и истории

  • Intel и Apple Silicon, минимальная версия — macOS Monterey 12

  • Как можно меньше автоматических тестов: только там, где результат нельзя надёжно проверить глазами

После этого началась разработка короткими горизонтальными итерациями.

Как выглядел вайбкодинг на практике

Обычно под вайбкодингом представляют запрос вроде «сделай мне приложение для камеры» и волшебную кнопку Build. У меня всё выглядело иначе.

Цикл был примерно таким:

  1. Я описывал одно конкретное поведение человеческим языком

  2. Codex исследовал существующий код и предлагал реализацию

  3. Он менял проект и собирал приложение

  4. Я проверял результат на реальной камере

  5. Возвращал очень короткую, но фактическую обратную связь: «рывками», «чёрный экран», «таймлайн встал», «кадр зависает»

  6. Мы изучали логи, формулировали гипотезу, меняли один параметр или откатывались

Иногда моя реплика состояла буквально из двух слов: «Черный экран». Но за ней стояла проверка конкретного сценария на конкретном железе. AI не мог увидеть, насколько естественно движется человек в кадре, совпадает ли положение таймлайна с видео и начинается ли воспроизведение после быстрой перемотки. Это оставалось моей работой.

При этом Codex снимал главный барьер — незнакомый стек. Мне не приходилось сначала несколько недель изучать синтаксис Swift, жизненный цикл SwiftUI, CocoaPods, Core ML и устройство macOS bundle. Я формулировал ожидаемое поведение на языке продукта, а AI переводил его в код и команды.

Опыт с Vue всё равно оказался важен. Состояние интерфейса, компоненты, асинхронные операции, гонки запросов, отмена устаревших действий — всё это знакомые frontend‑задачи. Я не знал нужных API Swift, но понимал, когда состояние приложения ведёт себя неправильно и какой результат должен видеть пользователь.

Что получилось

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

Есть кнопки воспроизведения и паузы, шаги назад и вперёд на 10 и 30 секунд, переход к прямому эфиру и календарь. В календаре недоступные дни и часы нельзя выбрать, а если точной записи нет, приложение ищет ближайший существующий фрагмент.

Во время перемотки MiniCam показывает сохранённые кадры, чтобы пользователь не смотрел на мигающий чёрный экран. Кэш можно хранить во внутренней папке или перенести на внешний диск. Если диск отключён, приложение временно возвращается во внутреннее хранилище, а после подключения объединяет данные.

Календарь
Календарь

Отдельная правая панель собирает события движения. Приложение фиксирует не просто присутствие человека или машины, а начало движения: неподвижный автомобиль не должен постоянно создавать новые карточки. В карточке сохраняются время и кадр, а нажатие переводит архив к этому моменту.

Можно выбрать режим «только люди» или «люди и транспорт», срок хранения событий — один, три или семь дней — и вручную очистить историю.

Панель события
Панель события

Также приложение умеет сохранять текущий кадр в PNG. На паузе можно выделить на таймлайне непрерывный интервал длительностью до 30 минут и выгрузить его одним MP4-файлом.

Всё работает локально. Нет сервера MiniCam, облачного аккаунта, телеметрии и подписки. Пароль камеры хранится в Keychain macOS.

Из чего всё состоит

Если перевести архитектуру на язык frontend‑разработчика, SwiftUI отвечает за view и состояние интерфейса, а интеграции с камерой и видео вынесены в отдельные сервисы.

                         ┌─> VLCKit ─> прямой эфир / архив
PoE-камера ─> RTSP ──────┤
                         └─> кадры ─> YOLOX/Core ML ─> события

PoE-камера ─> ISAPI ─> список записей ─> единый таймлайн

выбранный интервал ─> FFmpeg ─> MP4-файл

Основные инструменты и компоненты:

  • SwiftUI и Xcode — нативное приложение для macOS

  • VLCKit — прямой эфир и воспроизведение RTSP‑архива

  • Hikvision ISAPI — поиск записей на microSD

  • FFmpeg — экспорт выбранного интервала в MP4

  • YOLOX‑Tiny и Core ML — локальное распознавание людей и транспорта

  • Keychain — хранение пароля

  • security‑scoped bookmarks — постоянный доступ к выбранным внешним папкам

  • Git — контроль экспериментов и быстрые откат

  • Codex — планирование, реализация, сборка, диагностика, тесты и подготовка релиза

В результате проект вырос до 52 Swift‑файлов и примерно 7 500 строк основного кода. Ещё около тысячи строк находятся в 16 файлах тестов. В финальном прогоне прошли 43 unit‑теста.

Самое сложное — не Swift

Синтаксис нового языка оказался не главной проблемой. Самыми трудными стали особенности потокового видео и самой камеры.

Архив на самом деле не единое видео

Камера хранит запись отдельными сегментами. ISAPI возвращает список интервалов, а RTSP открывает конкретный участок. Чтобы пользователь видел одну шкалу, приложение должно объединить эти интервалы, выбрать правильную запись для нужного времени и незаметно перейти к следующему сегменту.

При этом край архива постоянно растёт: камера продолжает записывать. Новые данные нужно опрашивать каждые 15 секунд не только в прямом эфире, но и пока пользователь смотрит старую запись. Одна из ошибок проявлялась так: воспроизведение доходило до устаревшего края архива, зависало и внезапно прыгало в эфир.

Перемотка и чёрный экран

Перемотка породила больше всего итераций. Видео то вставало на паузу, то не продолжалось после отпускания таймлайна, то показывало только исходный кадр, то мигало чёрным.

Мы пробовали разные жизненные циклы плеера, предварительные кадры, сериализацию переходов и настройки пропуска опоздавших кадров. Некоторые исправления помогали Intel и ломали Apple Silicon. Другие убирали скачки в эфире, но давали чёрный архив.

Был и показательный ложный след. Проблема выглядела архитектурной: разные результаты на Intel, Apple Silicon и под Rosetta. Но в один момент выяснилось, что запущено несколько копий приложения, а оставшийся процесс FFmpeg занимал RTSP‑сессию камеры. После его остановки «архитектурный» чёрный экран исчез.

В финальной конфигурации прямой эфир использует TCP, а архив — UDP. Это не универсальная истина для всех камер, а результат тестов именно с моей моделью и сетью.

У камеры ограничены ресурсы

Приложение хочет одновременно показывать видео, обновлять архив, получать кадры для плавной перемотки, анализировать движение и иногда экспортировать ролик. Но камера допускает очень мало параллельных RTSP‑сессий. Если открыть VLC, браузер и несколько MiniCam, можно получить 453 Not Enough Bandwidth.

Поэтому фоновые операции пришлось координировать. Например, во время экспорта MiniCam освобождает соединение плеера, получает архив через FFmpeg, а затем восстанавливает прежний режим.

Распознавание — это не просто «объект найден»

Первая версия могла видеть человека, но пропускать быстрый проход или создавать события для неподвижных объектов. Пришлось разделить две задачи: сначала найти изменившуюся область между кадрами, затем проверить её моделью распознавания.

Анализируются только новые 15-секундные участки архива, появляющиеся во время работы приложения. Старый архив задним числом не сканируется, прямой эфир тоже не используется для детекции. Это сознательное ограничение: оно уменьшает нагрузку на старый Intel Mac и не создаёт ещё одно постоянное подключение к камере.

Кто что делал

Мне не хочется выдавать этот проект ни за полностью ручную разработку, ни за автономную работу AI.

Codex действительно написал почти весь Swift‑код. Он создавал структуры проекта, подключал VLCKit, реализовывал запросы ISAPI, работал с Core ML и FFmpeg, запускал сборки и тесты, читал ошибки, готовил universal‑релиз и документацию. Без него я бы сначала долго осваивал сам стек, а многие платформенные детали вообще не знал бы где искать.

Но продуктовые решения не возникали из кода. Я определял, что перемотка должна ощущаться единым видео, что неподвижные люди и машины не являются событиями, что таймлайн должен сворачиваться, что скриншот сохраняется без элементов интерфейса и что приложение обязано работать на Intel Mac с Monterey.

Я же решал, когда результат неприемлем. Фраза «работает» от компилятора ничего не говорит о плавности видео. Несколько раз мы возвращались на рабочий коммит после серии ухудшений. AI мог быстро предложить следующую гипотезу, но решение «продолжаем» или «откатываем» принимал я.

В этом смысле мой предыдущий опыт разработки оказался важнее знания Swift. Я умел декомпозировать требования, замечать регрессии, ограничивать область изменений и не смешивать визуальную проверку с unit‑тестами.

Два дня против нескольких месяцев

По истории Git первый проектный документ появился 1 сентября в 13:14, а основной этап закончился 2 сентября примерно в 17:44. Получается около 28,5 часа по календарю и 76 небольших коммитов. Среди них были не только функции, но и спецификации, диагностические изменения, исправления и точки отката, поэтому количество коммитов здесь не является мерой производительности.

Насколько сложно было бы написать аналог без AI? Моя оценка после завершения проекта — примерно 8 из 10. Сам интерфейс не уникально сложный, но сочетание RTSP, постоянно растущего архива, временных меток, ограничений камеры, локальной ML‑модели, экспорта и двух процессорных архитектур требует специализированного опыта.

Одиночная традиционная разработка такого набора функций могла бы занять от трёх до шести месяцев — в зависимости от опыта инженера с macOS и мультимедиа. Это не научно измеренный срок и не утверждение, что любой Swift‑разработчик обязательно потратил бы полгода. Это ориентир масштаба задачи.

AI сократил для меня путь до рабочей версии примерно до двух дней, потому что почти полностью убрал стоимость входа в незнакомый технологический стек. Но он не отменил время на проверку. Значительная часть этих двух дней состояла из повторяющегося цикла «собрать — запустить — перемотать — увидеть ошибку — описать её — попробовать снова».

Подготовка открытого репозитория, двуязычного README, лицензий зависимостей и GitHub Release происходила позже и в эти два дня не входит.

Что осталось за кадром

MiniCam пока beta. Приложение полноценно проверялось прежде всего с Hikvision DS-2CD2043G2-IU. Другие модели могут отличаться RTSP‑путями, ответами ISAPI, ограничениями сессий и поведением архива.

Сборка не нотарифицирована Apple: у проекта пока нет платного Developer ID, поэтому при первом запуске её приходится вручную разрешать в настройках безопасности macOS. Есть технический долг, крупные координирующие компоненты и предупреждения новой версии Swift о строгой изоляции потоков. А проверка на новой камере почти наверняка обнаружит новые пограничные случаи.

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

Форма настроек
Форма настроек

Что я понял о вайбкодинге

Главный результат эксперимента для меня не в том, что AI пишет Swift быстрее человека. Важнее то, что граница доступных одному разработчику задач заметно сдвинулась.

Раньше идея нативного macOS‑клиента с RTSP, Core ML и FFmpeg остановилась бы на оценке времени изучения стека. Теперь я мог начать с поведения продукта и получать обратную связь от работающей программы почти сразу.

Но чем ближе проект к реальному железу, сети, видео и многопоточности, тем меньше работает подход «просто довериться модели». Нужен наблюдаемый результат, короткие итерации, контроль версий и готовность отменить красивое, но неправильное решение. Нужно понимать не конкретный синтаксис, а инженерные причинно‑следственные связи.

Мой вывод: вайбкодинг особенно силён не вместо опыта разработчика, а поверх него. Vue не научил меня писать на Swift, но научил работать с состоянием, асинхронностью, интерфейсами и требованиями. AI закрыл языковой и инструментальный разрыв. Вместе этого оказалось достаточно, чтобы за два дня превратить раздражение от тормозящей камеры в настоящее приложение.

Комментарии (0)