Задача: после упаковки SpriteAtlas в Unity вы получаете серию PNG-атласов для UI или 2D. Перед выкладкой в репозиторий ассетов или CDN команда обычно требует три вещи: размеры кратны степеням двойки (POT), прозрачность реально присутствует в файле (RGBA там, где это контракт), и вес не вылезает за max_bytes на платформу. На удалённом Mac с OpenClaw это удобно автоматизировать: узкий Gateway, скрипты в git и наблюдатель каталога, который не лезет в произвольные пути.
Стратегия мониторинга каталога · Шаблоны пакетных команд · Повторы при сбоях и архив логов · FAQ по устранению неполадок
Контекст сеток и ретины для спрайтов сверяйте с матрицей «PNG-спрайты, CSS-срезы и ретина на удалённом Mac»; общий каркас watch, JSONL и ретраев — в «мониторинг PNG, повторы и архив логов»; если после исправления геометрии остаётся проблема веса — «pngquant и zopflipng на M4». Установку шлюза зафиксируйте по «установке OpenClaw на поддерживаемых платформах».
Стратегия мониторинга каталога
Пример структуры. В корне проекта Unity заведите Exports/SpriteAtlas/ и запретите ручные сохранения мимо этой папки в README пайплайна. Editor-скрипт или post-step билда пишет, например, atlas_hud_1024.png.tmp, дожидается завершения FileStream и выполняет mv в atlas_hud_1024.png. Наблюдатель реагирует только на финальное имя — так вы отсекаете половину гонок с недописанными байтами.
Где крутить watch. Путь должен быть абсолютным и лежать на локальном томе Apple Silicon, не в каталоге iCloud Drive/Dropbox: синхронизаторы дают «дребезг» событий и маскируют реальный EOF. На выделенном удалённом Mac заведите пользователя воркера и дерево ~/atlas_jobs/<job_id>/inbox, куда Unity копирует или сразу пишет экспорт для ночной приёмки.
fswatch и тихое окно. После brew install fswatch не запускайте инспекцию на каждое событие: буферизуйте метки времени и ждите тихое окно (практичный диапазон 8–20 секунд без новых событий по маске *.png). Дополнительно проверьте стабильный размер — два подряд одинаковых stat -f%z с паузой 0,5 с — прежде чем читать метаданные через ImageMagick. Поверх очереди держите single-flight lock-файл воркера, чтобы две параллельные сборки Unity не породили два конкурирующих прогона find по одному дереву.
OpenClaw. Gateway оставьте на 127.0.0.1, а вызов навыка пусть передаёт только whitelist-параметры: корень, путь к YAML с порогами, job_id. Это согласуется с подходом «Gateway → Shortcuts / shell для пакетов PNG»: в чат не кладите длинные однострочники — только ссылку на коммит скрипта.
Шаблоны пакетных команд
Ниже — минимальный проход по всем PNG в корне экспорта. Переменные окружения: ATLAS_EXPORT_ROOT — каталог с атласами; MAX_BYTES — жёсткий потолок; REQUIRE_ALPHA=1 — требовать подстроку rgba в выводе magick identify (подгоните под ваш контракт: иногда допустим srgba). Логи пишутся в LOG_DIR построчно в JSONL для последующего grep и архивации.
#!/usr/bin/env bash
set -euo pipefail
ROOT="${ATLAS_EXPORT_ROOT:?}"
MAX_BYTES="${MAX_BYTES:-1200000}"
REQUIRE_ALPHA="${REQUIRE_ALPHA:-1}"
LOG_DIR="${LOG_DIR:-./logs}"
mkdir -p "$LOG_DIR" ./quarantine
is_pot() { local n="$1"; [[ "$n" =~ ^[0-9]+$ ]] && (( (n > 0) && (n & (n-1)) == 0 )); }
while IFS= read -r -d '' f; do
[[ "$f" == *.png ]] || continue
w=$(magick identify -format '%w' "$f")
h=$(magick identify -format '%h' "$f")
ch=$(magick identify -format '%[channels]' "$f")
bytes=$(stat -f%z "$f")
ok=1
is_pot "$w" || ok=0
is_pot "$h" || ok=0
[[ "$REQUIRE_ALPHA" == "1" && "$ch" != *rgba* ]] && ok=0
(( bytes <= MAX_BYTES )) || ok=0
printf '{"file":"%s","w":%s,"h":%s,"channels":"%s","bytes":%s,"ok":%s}\n' \
"$f" "$w" "$h" "$ch" "$bytes" "$ok" >> "$LOG_DIR/atlas-scan.jsonl"
[[ "$ok" -eq 1 ]] || mv "$f" "./quarantine/$(basename "$f").$(date +%s).png"
done < <(find "$ROOT" -type f -name '*.png' -print0)
Экземпляр. Для мобильного UI-гейта возьмите MAX_BYTES=900000 для 2048×2048 RGBA после lossless-оптимизации; для веб-спрайтлиста — отдельная строка в YAML, чтобы не смешивать платформы. Строки с "ok":0 уже лежат в quarantine/ с суффиксом времени — дизайнер открывает Unity, правит packing или текстуру, пересобирает и снова кладёт файл в экспорт без ручного поиска «какой из тридцати упал».
Расширение. Если нужно отсечь не-POT ещё до magick, заведите белый список разрешений в YAML (allowed: [512,1024,2048]) и сравнивайте пары (w,h) множеством, а битовую маску POT оставьте как запасной контроль для нестандартных атласов.
| Платформа / сценарий | Пример max_bytes | Комментарий |
|---|---|---|
| iOS UI, 2048 POT RGBA | 0,9–1,4 МБ | После lossless; тяжелее — искать пустые поля атласа |
| Web спрайтлист 1024² | 0,35–0,7 МБ | Отдельный ключ YAML, не смешивать с мобильным |
| Desktop HUD 4096 POT | по смете CDN | Сравнивайте с медианой ночных билдов |
Если identify возвращает srgba или rgba, заранее опишите в контракте, что считать «достаточной альфой»: для строгого UI часто хватает проверки подстроки rgba, для контента с цветовым профилем — явно разрешите srgba и добавьте вторую строку в YAML, чтобы скрипт не ломал легитимные файлы.
Повторы при сбоях и архив логов
Классы сбоев. Разделяйте транзиенты (занятость файла, краткий отказ диска, гонка с антивирусом) и ошибки данных (POT, альфа, вес). Для транзиентов применяйте экспоненциальный backoff с потолком, например 2 с → 4 с → 8 с, максимум 60 с, не более трёх попыток на один trace_id. Для POT/альфы/size не запускайте слепой цикл повторов: файл уходит в quarantine, в JSONL пишется reason_code из множества pot, alpha, size, и очередь ждёт нового артефакта от Unity.
JSONL и ротация. Каждый прогон добавляет строку; ночной cron сжимает вчерашний файл: gzip -9 logs/atlas-scan-$(date -v-1d +%F).jsonl на macOS или эквивалент по расписанию. Успешные партии можно агрегировать в archive/ГГГГ-ММ-ДД/summary.json с числом проверенных файлов и хэшем каталога. Политика близка к материалу про Skills UI и watchdog экспорта PNG: дежурный читает один формат лога, а не три разных чата.
Связка с launchd. Отдельный plist для наблюдателя и отдельный для воркера очереди с ThrottleInterval снимают шторм при массовом реимпорте текстур; переменные среды для токена Gateway продублируйте в plist один в один с ручным SSH-сеансом, иначе получите расхождение «вручную работает, по ночам падает».
FAQ по устранению неполадок
POT выполняется, но картинка «мыльная». Это не про файл на диске, а про содержимое: проверьте Pixels Per Unit и исходное разрешение спрайтов в атласе. Инспектор POT не заменяет визуальный QA — добавьте в манифест ожидаемый PPU для ключевых экранов.
Размер файла плавает между билдами без смены арта. Чаще всего меняется пресет текстуры или платформенный override; закрепите TextureImporter и SpriteAtlas packing в ветке и сравнивайте байты с медианой прошлой успешной ночи, а не только с жёстким потолком.
Сбои только ночью. Проверьте сон хоста, отмонтирование внешнего тома и конкуренцию с резервным копированием; поднимите тихое окно и логируйте mount в начале задачи.
Gateway возвращает отказ в доступе. Сузьте allowlist до Exports, logs, quarantine и пути к интерпретатору; убедитесь, что plist запускает ту же UID, что видит файлы Unity.
Итог: атомарный экспорт .tmp→.png, тихое окно fswatch и single-flight, затем единый bash-проход с magick identify и stat, причины в JSONL и gzip-архив. Контрактные страницы MacPng — аренда и покупка, тарифы и узлы, помощь по SSH и VNC — вход в личный кабинет не обязателен, чтобы сравнить планы и подключение.
Инспекция SpriteAtlas на выделенном удалённом Mac
Вынесите watch и приёмку PNG-атласов на стабильный Apple Silicon, оставьте узкий Gateway и единый журнал для дизайна и билда.