Читать в начале каждой итерации, обновлять в конце. Это память между проходами (Ralph-loop) — контекст не держим «в голове».
M3 — Рантайм масок на CEF (офскрин-Chromium) → камера, без фриза.
CEF Phase 3 — живая маска идёт в виртуалкамеру и НЕ виснет, когда приложение спрятано. Статус: 🟡 пайплайн собран и доказан headless; ждёт финальной проверки пикселей в камере глазами.
- Симптом фриза: WKWebView троттлит rendering/requestAnimationFrame, как только окно «невидимо» (⌘H, перекрытие, офскрин) → в Meet кадр застывает. Это следствие.
- Корень №1 (фриз): неправильный рантайм. WebKit нельзя рендерить вне видимого окна. Производственный паттерн (OBS browser source) — headless CEF (Chromium) с offscreen-рендерингом: окна нет вообще → понятия «видимость» нет → не виснет.
- Корень №2 (движок зависал на старте + 20 запросов пароля): Chromium лез в macOS Keychain «Safe Storage» при старте и ЖДАЛ ответа на запрос пароля. Запуск из скрипта → отвечать некому → движок висел; меняющаяся подпись → новый запрос каждый раз. Фикс (подтверждён доками CEF): флаги
--use-mock-keychain+--password-store=basic→ Chromium не трогает Keychain. После фикса движок стартует чисто, без пароля. - Корень №3 (движок не мог писать в камеру): движок не в app-group → CMIO sink (app-group-scoped) его не пускал. Фикс: движок пишет кадры в общую память (mmap), а в камеру их пушит приложение (оно в app-group, путь доставки уже проверен).
M1 / Итерация 1 — камера с тест-паттерном видна в Meet. Статус: ✅ ЗАКРЫТА (риск #1 убит, 2026-05-30).
- Зафиксирована архитектура (виртуальная камера / CMIOExtension), отвергнут Chrome-extension.
- Оформлена спека M1 (
SPEC.md). - Написан код Итерации 1:
CameraExtension/— рабочий CMIOExtension с тест-паттерном (SMPTE-полосы + бегущая линия + брендлейбл + живые счётчики), 1280×720@30, BGRA. Файлы:CameraProvider.swift,Config.swift,main.swift,Info.plist, entitlements.MEETAMASK/— SwiftUI host-app +ExtensionManager(активация/деактивация черезOSSystemExtensionRequest).- Сборка через
xcodegen(project.yml).
- Подпись и активация доведены до рабочего состояния (2026-05-30):
- Bundle id:
com.meetamask.app+ extensioncom.meetamask.app.CameraExtension, Team 6D6948Z4MW (индивидуальный, не org). - Подпись: Automatic / Development (серт
Apple Development, auto-provisioning profile с entitlementcom.apple.developer.system-extension.install). Developer ID + нотаризация — отложено до M4 (раздача). - App скопирован в
/Applications, запущен оттуда → активация прошла, одобрено в System Settings.
- Bundle id:
- ✅ US-1 (риск #1) ПОДТВЕРЖДЁН: в Google Meet (Chrome, macOS 26) камера «MEETAMASK Camera» видна и стримит тест-паттерн (не чёрный экран). Проверено визуально в живой встрече.
- Системная проверка (Confirmed):
systemextensionsctl list→com.meetamask.app.CameraExtension (0.1/1) … [activated enabled].system_profiler SPCameraDataType→MEETAMASK Camera(Model ID «MEETAMASK Virtual Camera»).
- dev-mode недоступен при SIP on.
systemextensionsctl developer onпадает с ошибкой SIP. Решение: НЕ трогаем SIP, идём через настоящую подпись (Development). Доказано: расширение активировалось при включённом SIP. - Сборка была ad-hoc + старый bundle id (
ai.overchat.meetamask.*). Решение: чистая пересборка подcom.meetamask.appс реальной подписью (Mac зарегистрирован, профиль выпущен). - Системное расширение активируется только из
/Applications(ошибка при запуске из DerivedData). Решение: копировать app в/Applicationsи запускать оттуда.
Всплывающего окна НЕТ. Путь к тумблеру: System Settings → General → Login Items & Extensions → секция Extensions (внизу) → переключатель By Category → Camera Extensions → ⓘ → включить тумблер MEETAMASK. После пересборки с новой версией расширения может потребоваться повторное одобрение там же.
engine/— отдельное headless-CEF-приложение (CMake/Ninja, CEF 148). Рендерит страницу маски офскрин (SetAsWindowless,windowless_frame_rate=30),OnPaintBGRA → пишет в общую память.engine_app.cc— командная строка:--use-mock-keychain,--password-store=basic(фикс зависания/паролей),--enable-media-stream,--use-fake-ui-for-media-stream(авто-allow вебки), anti-throttle флаги.engine_handler.{h,mm}—OnLoadEndинъектит: (1) выбор РЕАЛЬНОЙ вебки (не «MEETAMASK Camera», иначе петля) + (2) авто-клик#startBtn.OnPaint→FrameSHM.Write.frame_shm.{h,mm}— mmap-файл: header{seq:u64, w:u32, h:u32}(16б) + 1280×720×4 BGRA. Write копирует и бампает seq.
- Приложение (
MEETAMASK/):EngineFrameReceiver.swift(новый) — запускает движок (Process) с маской и--shm; mmap; таймер 30fps читает кадр →CameraFeeder.makeSampleBuffer(fromBGRA:)→enqueue.ProcessInfo.beginActivity(idleSystemSleepDisabled) — нет App Nap. Превью в приложении из тех же кадров.CameraFeeder.swift— добавленmakeSampleBuffer(fromBGRA:width:height:)(копия с учётом stride из общей памяти в pool-pixelbuffer).MaskGalleryView.swift— вкладка «Маски» переведена на движок: превью = кадры движка; поток выживает при смене вкладок и спрятанном приложении (нет.onDisappear stop).MEETAMASK.entitlements— снятapp-sandbox(sandbox блокируетProcess-запуск движка и общий файл). app-group СОХРАНЁН. Производственный паттерн (OBS/Discord). Раздача — Developer ID + нотаризация (sandbox не нужен).
- Доказано фактами (headless):
- расширение осталось
[activated enabled]после снятия sandbox → app-group живёт без песочницы (Confirmed). - приложение само поднимает движок с бандл-маской
ar-dr-strange(Confirmed: видны все CEF-процессы). - движок рендерит живую маску: вебка + MediaPipe-трекинг рук + AR (Confirmed: кадр выгружен в PNG, видно лицо/руки/HUD/эффект).
- поток кадров в общую память живой ~30fps (Confirmed: seq растёт 123→…→5478).
- вебка прошла в движок без отдельного промпта — TCC-камера атрибутировалась родительскому приложению (responsible process), у которого доступ уже есть (Confirmed эмпирически).
- расширение осталось
- Финальная проверка глазами (нужен пользователь, headless нельзя — терминалу не выдан camera-TCC): Photo Booth / Meet с «MEETAMASK Camera» →
- видно маску (я + неон + руки)?
- главный тест: ⌘H спрятать приложение / Meet на весь экран → маска ПРОДОЛЖАЕТ двигаться (не виснет)?
- Если в камере не маска: добавить
NSLogвCameraFeeder.connect/enqueue+ релей расширения → увидеть push вlog show(headless-диагностика без камеры). - Затем: бандлить движок внутрь app (
Contents/Resources/MEETAMASKEngine.app) вместо dev-пути; убрать неиспользуемыйMaskStudio.swift(мёртвый после перехода на движок); Phase 4 — проброс кликов по темам в движок; Phase 5 — GPU OSR (IOSurface) для стабильных 30fps. - TDD-юниты (frame gen, queue, fps) — остаётся долгом.
- Итерация 2 (sink-стрим + релей + app кормит камеру) — реализовано:
CameraFeederпушит в sink черезCMSimpleQueue, релей sink→source в расширении. Путь доставки проверен (в прошлой сессии маска дошла до Photo Booth).
- Meet зеркалит self-view → порядок полос на экране обратный (это норм).
- Meet накладывает свой portrait/background-blur поверх кадра → лёгкое размытие тест-паттерна. На фиделити реального видео смотрим в Итерации 3.
Все три срабатывают ТОЛЬКО когда «MEETAMASK Camera» одновременно открывают 2+ приложения (Meet + Photo Booth/Zoom). Обычный сценарий «один звонок» их не задевает. Подтверждено двумя независимыми ревью (codex native + 21-агентный проход, 2026-06-10). Все в одном файле
CameraExtension/CameraProvider.swift— один заход когда дойдём.
- Заморозка при 2+ потребителях (F9):
sinkShouldBeFed(CameraProvider.swift:114) →_streamingSourceCounter <= 1; при 2+ зрителях приложение перестаёт кормить sink, все мрут. Фикс:> 0. - Утечка/дубль таймера (codex P2):
startStreamingSource/startStreamingSinkперезаписывают_sourceTimer/_sinkTimerбез отмены старого;stopгасит только последний. Фикс: создавать таймер только на переходе 0→1, старый cancel. - Несинхронные счётчики (F8):
_streamingSourceCounter/_streamingSinkCounterчитаются/пишутся из разных очередей без lock.
- Симптом месяцами был неуловим и прерывист. По скрину юзера это НЕ его Chrome, а Chromium нашего движка (кнопка «Customize Chromium», не «Customize Chrome»; иконка вкладки — синий Chromium). Единственный Chromium в системе = MEETAMASKEngine.
- Корень: движок использовал ОДНУ общую папку профиля Chromium (
~/Library/Caches/ai.overchat.meetamask.engine, зашито вengine/main.mm). Когда одновременно живут два процесса движка (хост открыт дважды — вlog streamвидно два инстанса: host pid 44954+45030, engine 44978+45032), у Chromium срабатывает process-singleton: второй инстанс с той же папкой профиля просит первый открыть новое окно → пустой New Tab. Одиночный движок окна не даёт — поэтому в single-launch тестах (и у меня, и в прошлых сессиях) не воспроизводилось. - Диагностика:
log stream(launchservicesd + runningboardd + Google Chrome + com.meetamask.app subsystem) на живом репро + скрин юзера +lsappinfo(движок = UIElement, LSUIElement=1 → не док-приложение, значит окно — не «нормальный» foreground-режим, а singleton-форвард). - Фикс (
engine/main.mm, коммит 564b125): папка профиля выводится из per-instance shm-ключа — уникальна на инстанс хоста, но СТАБИЛЬНА между переключениями масок (HTTP-кэш MediaPipe переиспользуется, не перекачивается на каждый свитч). Два хоста → две папки → singleton не сталкивается → окна нет никогда. + best-effort чистка папок мёртвых сессий (>24ч). - Проверено: два движка одновременно (distinct shm) → разные
user-data-dir, 0 окон на экране (CGWindowList по owner-name), обаwindowless=1+ кадры идут. - Прод: пересобран (ninja) →
package-engine.sh(Developer ID + hardened runtime) →notarize.sh(Accepted, id 4cdb3fc4) → staple → залит в релиз v0.2 (clobber). Контроль скачиванием сdl.meetamask.com/engine:spctl accepted, Notarized Developer ID+ staple OK + бинарь 2026-07-05 23:06. Локально в App Support тоже стоит фикс.
- Прод (
dl.meetamask.com/app→ Release v0.2MEETAMASK.zip) отставал от main на 15 коммитов (лежал билд от 11 июня без новых масок). Пересобран и залит свежий хост: 56 папок масок, все 7 новых пресетов (chomp, callwrapped, sandbox, faceoff, facesimon, goblin, leanin). - Путь — строго по правилу от 2026-06-11:
xcodebuild archive→-exportArchive(method=developer-id,build/exportOptions-devid.plist) →dist/notarize.sh(профильmeetamask) → staple → zip →gh release upload v0.2 --clobber. Артефакты:build/rel-20260702/. - Заминка: нотаризация сперва дала
HTTP 403 — agreement expired; founder принял обновлённое соглашение на developer.apple.com → повтор прошёл (Accepted, id c6a3bd9e). - Проверено сквозняком как юзер: скачан с
dl.meetamask.com/app(1.46 МБ) →spctl: accepted, Notarized Developer ID+stapler validate OK+ hardened runtime, без get-task-allow + 56 масок, 7/7 новых на месте. main запушен в origin (045b69a..58f839b). - Движок в релизе не трогали — его исходники не менялись с 2026-06-03, прод-зип актуален.
- Примечание: в
/Applicationsна маке founder'а стоит dev-сборка (Apple Development, от локальной пересборки 28 июня) — для локальной работы это норм; прод-юзеры получают нотаризованный билд.
- Баг (мой промах): билд от
dist/sign-host.shпроходил Gatekeeper (spctl accepted), но macOS/AMFI убивал его на старте (SIGKILL, RBS 163). Причина — у app есть системное расширение, чьи restricted-entitlements требуют Developer ID provisioning profile, которого ручная подпись не вшивала. «Подпись принята» ≠ «запускается». Раньше я этого не проверял (тестировал только spctl), отсюда ложное «раздача живая». - Фикс: founder вошёл в Apple ID в Xcode →
xcodebuild -exportArchive(method=developer-id,-allowProvisioningUpdates) сам выпустил профильMac Team Direct Provisioning Profileи вшил его → нотаризация (id 445fb64d) → staple → залит в релиз v0.2 (clobber). - Проверено сквозняком: скачал с
dl.meetamask.com/appкак юзер → распаковал → бинарь запускается и живёт (AMFI не убивает). Раздача наконец настоящая. - Правило на будущее: хост для раздачи собирать ТОЛЬКО через exportArchive (нужен Xcode-логин), НЕ через
sign-host.sh(он стрипнет профиль). Детали — в памятиproject_meetomask_repo. - Не проверено (нет чистой машины): активация Developer-ID-расширения на маке, который его раньше не видел.
- Домен: Cloudflare Worker
meetamask-dlнаdl.meetamask.com(зона meetamask.com; токены в Keychain:cloudflare_meetamask_workers,cloudflare_meetamask_dns; DNS AAAAdl→100:: proxied + routedl.meetamask.com/*). Редиректит на GitHub Release latest:https://dl.meetamask.com/app→ MEETAMASK.zip (хост, 844K)https://dl.meetamask.com/engine→ MEETAMASKEngine.zip (132 МБ)
- Хост-приложение: пересобран с новым URL движка (
dl.meetamask.com/engine, коммитc88e680), подписан Developer ID черезdist/sign-host.sh(БЕЗ Xcode-логина — ручной путь работает), нотаризован (Accepted, id 419a4b5d) + застейплен;spctl= Notarized Developer ID. Залит в релиз v0.2. - Обе цепочки скачивания проверены curl'ом (302 → файл, 206 на range).
- Осталось до MVP: (1) живой тест глазами — скачать с dl.meetamask.com/app как юзер, поставить, маска видна в Meet; (2) дёшево: проверка подписи движка при скачивании (F2).
- Код на GitHub: github.com/metawhisp/meetmask (public). Репо называется
meetmask(без одной «a»). - Движок собран → подписан Developer ID (Andrey Dyuzhov, 6D6948Z4MW, inside-out через
dist/package-engine.sh) → нотаризован + застейплен (dist/notarize.sh, профильmeetamask, статус Accepted) →spctl= «Notarized Developer ID». - Опубликован как Release
v0.2(assetMEETAMASKEngine.zip, 132 МБ). Скачивается без авторизации. EngineInstaller.sourceURLтеперь →https://github.com/metawhisp/meetmask/releases/latest/download/MEETAMASKEngine.zip(envMEETAMASK_ENGINE_URLвсё ещё оверрайдит для дева). Коммит7542615.- Старый мёртвый
dl.meetamask.app(NXDOMAIN) больше не используется → блокер №1 закрыт. - Осталось для «скачал → поставил → работает»: (1) собрать+подписать+нотаризовать ХОСТ-приложение (
dist/sign-host.sh+notarize.sh) и где-то выложить его на скачивание; (2) проверка подписи движка при скачивании (F2, дёшево); (3) живой тест глазами — маска доходит до Meet.
Новый пресет (вместо отклонённого WIPE OFF). Prototype/effects/registry/faceoff.js, id: FaceOff, FACE. Идея founder: пальцем хватаешь глаз/нос/рот, тащишь от лица — на месте остаётся пустая кожа.
- Как: полноэкранный фрагмент-шейдер красит камеру; для каждой смещённой части (1) заливает её исходное место кожей с ближнего landmark, (2) пересэмплит пиксели части в точке, куда утащили. Рука = курсор: щипок (большой+указательный) рядом с частью → захват; увёл — отпустил; притащил обратно к лицу → прилипла.
- Стек: две модели разом (FaceLandmarker 478 для частей + HandLandmarker для щипка — прецедент catattack).
wantsRawVideo=false, сами красим видео; ориентация по portalPull (coverUv+mirror). - §12-фикс: плоскость Tracker'а Y-DOWN → vUv.y растёт вниз;
toVuvотдаёт(px.x/W, px.y/H)(без 1−y), иначе позиции частей по Y инвертированы. Базовый кадр upright/не-зеркало (проверено?fake=1: TOP/L/«F» верно). - Верификация (
?fake=1+ инъекция uniform'ов): базовая ориентация ок; инъекция смещённой части → дырка кожей на месте + вырезанная часть в точке утаскивания (контент сэмплится верно). tests зелёные. ⚠ Живой захват (лицо+руки, размеры частей, ощущение щипка, качество заливки) — проверить на вебке. - Регистрация
index.js, шимMasks/faceoff/, тег,preview.webp. План-статус: #1 = FACE OFF (готов), #2 FACE SIMON / #3 GOBLIN / #4 LEAN IN — одобрены, в очереди; #5 MARIONETTE — отложен.
FLOW удалён из аппки (founder зарубил как невиральную абстракцию). Шипаем 3 виральных, interaction-as-core пресета: SANDBOX, CALL WRAPPED, CHOMP.
Третий пресет, чистая «interaction = весь фильтр» аркада. Prototype/effects/registry/chomp.js, id: Chomp, FACE.
- Еда падает сверху (🍎🍌🍒…); двигаешь головой → подставляешь рот, открываешь рот (jawOpen blendshape) → ешь (+1). 💣 — рот закрыт, иначе −1 жизнь. 3 жизни → GAME OVER с рекордом (localStorage
chomp_best). Разгон по очкам. - Рендер — 2D HUD-canvas в кадр (как callwrapped): падающие эмодзи, кольцо-хитбокс на рту (зелёное при открытом), счёт/жизни, попапы +1/−1, тряска/вспышка на бомбе. Камера сзади (
wantsRawVideo). Рот через mirror-awaretoPx→ хитбокс на твоём рту; §12 не трогаем. - Одна face-модель с blendshapes (через флаг базового
Tracker). Регистрацияindex.js, шим, тег,preview.webp. - Верификация (
?fake=1+ синтетический рот черезtick/play): съел еду → +1; съел бомбу → −1 жизнь; спавн/падение/куллинг ок; HUD рисуется в кадре вертикально. tests зелёные. ⚠ Вживую: порогjawOpen, размер хитбокса по лицу, fps.
Второй пресет под вирал (founder: «фильтр, который считает действия на созвоне и реагирует»). Prototype/effects/registry/callwrapped.js, id: CallWrapped, FACE.
- Детект на одной face-модели с blendshapes (включил вариант лоадера с кэшем по ключу:
loadFaceLandmarker({blendshapes:true}), чтобы не грузить blendshapes другим face-эффектам): улыбка (mouthSmile), разговор (jawOpenдисперсия), моргания (eyeBlink), брови (browUp), кивки/мотания (осцилляция носа), отвлёкся (нос ушёл от центра лица). Счётчики с дебаунсом/гистерезисом. - Реакция (всё в КАНВАС → видно в Meet + в записи): live-полоска счётчиков; эскалирующие ачивки-тосты (тон растёт мило→анимешно-ULT, уровни 1-4 с цветом/тряской/вспышкой); финальная карточка CALL WRAPPED (архетип THE CHARMER/YES-MAN/SKEPTIC/DAYDREAMER/MAIN CHARACTER/NPC + грид статы + CHAOS SCORE). Весь копирайт — английский (по запросу).
- Триггер карточки — «шок-лицо» (рот+брови) удержать ~1с; пока открыта — счёт на паузе, полоска/тосты скрыты.
- Регистрация в
index.js, шимMasks/callwrapped/, тег,preview.webp. - Верификация (preview-tools,
?fake=1+ синтетические blendshapes/landmarks черезtick()): счётчики растут (smile/blink/nod/talk/lookAway), тосты по тирам, карточка рендерится и помещается (CHAOS SCORE виден), HUD вертикально-корректен (flip не нужен). tests зелёные. ⚠ Вживую проверить: пороги мимики/кивков на реальном лице и fps.
Founder зарубил FLOW (и весь «алгоритмический арт») как невиральную заставку: «всё ярче сделал, но хуета осталась… не инстаграмная, в тиктоке не завиралится… взаимодействие должно быть ОСНОВНОЙ фишкой фильтра, а не тупой заглушкой». Урок записан в память [[feedback-viral-not-art]]. Новый критерий каждого пресета: про лицо, мгновенно понятно, есть «момент», взаимодействие = вся суть, просится на запись. FLOW 1.0/2.0 остаются в коде, но депрайоритезированы.
Первый пресет под новый критерий. «Ты — это физика»: Prototype/effects/registry/sandbox.js.
- ~170 шариков, кастомная 2D-физика (гравитация + стены + шар-шар через uniform-grid broadphase, 2 итерации релаксации). Рендер —
InstancedMeshcandy-шаров (шейдинг-спрайт + instanceColor) поверх живой камеры. - Управление = весь фильтр: наклон головы → направление гравитации (вся куча едет); голова и обе ладони — кинематические коллайдеры (двигаешь → расталкиваешь/подбрасываешь/ловишь); жесты: ✊ магнит (стягивает шарики), ✋ сдувает. Деградирует: нет лица → гравитация вниз; нет рук → только голова.
- Два детектора: база
Tracker{kind:'face'}+ доп.loadHandLandmarkerв setup;update()гоняет оба на кадр. - Доп. механики (2026-06-15): закрыл лицо рукой → гравитация переворачивается ВВЕРХ (
covered = !faceLms && hands>0); ✊ кулак ХВАТАЕТ шарики (heldBy, пружина к руке, без гравитации, носишь с собой), ✋ ладонь — отпускает+швыряет (доб. скорость руки). Проверено инъекцией: covered→gy<0; захват 17→держатся точно на руке при движении; раскрытие→released+летят. - Регистрация
index.js(id: Sandbox, FACE), шимMasks/sandbox/index.html, тег,preview.webp. - Верификация (preview-tools,
?fake=1): §12 — гравитация вниз пилит шарики у НИЗА (верно); тилт-гравитация (gx,gy) → куча уезжает в нужный угол; ✊-магнит → шарики залипают на руке против гравитации; коллизии/стены/пайл — ок; рендер чистый. Кадры прокачаны синхронно (hidden-tab rAF на паузе). ⚠ Не проверено вживую: связка реальное лицо/руки→коллайдеры (нужна вебка) и fps двух MP-моделей — проверить в живом тесте.
Цель: добавить «алгоритмические» интерактивные маски (вдохновение — generative-art инструменты: flow fields, reaction-diffusion, клеточные автоматы). Сгенерировано 3 идеи, каждая — отдельное семейство алгоритмов, управляемое телом юзера:
- FLOW — curl-noise flow field, рулится руками (✊ воронка / ✋ фонтан). ✅ СДЕЛАНО → 🔵 идёт FLOW 2.0 (founder: «должно быть в 10 раз прикольнее»). Вайб: чернила/аврора (холодная палитра, à la parallel.ai). План 4 фазы; Фаза 1 (рендер) — СДЕЛАНА.
- MORPHOGEN — reaction-diffusion (Gray-Scott), узоры Тьюринга прорастают из движения. ⏳ план (ping-pong FBO;
ctx.rendererуже проброшен). - LIFEFORM — клеточный автомат (Game of Life), засев из силуэта/движения. ⏳ план (та же ping-pong-инфра, что у #2).
- Переписан рендер-стек в
flow.js: ушли от 1px-линий к накопительному FBO (длинные шёлковые шлейфы; затуханиеTRAIL_FADE= память трейла, без per-particle истории) + сепарабельный bloom (half-res) + мягкие толстые спрайты (THREE.Points, аддитив). Финальный композит сам красит камеру (wantsRawVideo=false,sampleVideo+ Y-flip как portalPull) → затемнение/десатурация/виньетка; холодная палитра-аврора (HSL band cyan→violet). - 5000 частиц; «свечение» даёт bloom (а не пересвет трейла → нет clipping в белое). Поле и руки — как в 1.0.
- Верификация (preview-tools,
?fake=1): §12 ориентация ок (TOP/L/F вертикально, не зеркало); FBO+bloom+композит рендерятся; цвет холодный, структура curl читается. Кадры прокачаны синхронно (hidden-tab rAF на паузе). Превью обновлено под новую палитру. - ⏳ Дальше (по решению founder): Фаза 2 (эмиссия из силуэта + покраска от видео + огибание лица), Фаза 3 (струи из пальцев + жест-режимы), Фаза 4 (motion-energy/грейд).
Prototype/effects/registry/flow.js—Tracker{kind:'hand'}; 2400 частиц с трейлами (одинLineSegments, additive), поле = curl аналитической stream-функции (divergence-free → нет слипания). Руки = вихрь + радиальная сила (знак по «открытости» ладони из landmarks). Без рук — амбиент-поток. Камера видна позади (wantsRawVideo), затемнение plate'ом; ничего не красит черезuVideo→ §12 соблюдён by-construction.- Регистрация:
Prototype/effects/index.js(id: 'Flow', categoryHAND). Шим:Masks/flow/index.html→autostart=Flow. Тег:Masks/tags.json. Превью:Masks/flow/preview.webp(из registry-preview()). - Верификация (браузер, preview-tools): грузится без ошибок;
setupок; §12 ориентация верна (?fake=1→ TOP/BOTTOM/L/R, «F» читается); трейлы рендерятся (33600 верт., цвет ок), поле закручивается. Прогонtests/run-all.sh— зелёный. Примечание: headless-вкладкаdocument.hidden=true→ rAF на паузе; для проверки кадры прокачивались синхронно из eval.
- Архитектура: виртуальная камера (CMIOExtension). Chrome-расширение отвергнуто.
- Оптимизируем под качество + удобство конечного пользователя.
- Team ID: 6D6948Z4MW (индивидуальный). Bundle:
com.meetamask.app. - Подпись сейчас: Development (auto). Developer ID + нотаризация — на M4.
- SIP не трогаем; dev-mode не используем.