Детская веб-мультстудия для рисования и покадровой анимации. Главный экран «Мои мультики» позволяет создавать, открывать, переименовывать, копировать и удалять независимые локальные проекты.
- Кисть, ластик, заливка, фигуры, текст и стикеры.
- Перемещение, масштабирование, отражение и перекрашивание выделенных рисунков; текст и стикеры сохраняются как отдельные объекты.
- Создание, копирование, удаление и перестановка кадров, Undo/Redo, воспроизведение с выбором скорости.
- Импорт PNG, JPEG, WebP и GIF в выбранный кадр с сохранением пропорций. Для анимированного GIF импортируется изображение, а не последовательность кадров.
- Экспорт текущего кадра в PNG и мультика из нескольких кадров в GIF.
- Подсказки-шаблоны для обводки, симметрия, распознавание простых контуров, палитра и любимые цвета.
- Карточки с превью первого кадра, количеством кадров и датой изменения; сортировка по последнему изменению.
- Подтверждение удаления, сообщения об ошибках и повторная попытка сохранения.
- Настройки инструментов на небольших экранах открываются кнопкой «Настройки».
React 19, TypeScript, Vite, Tailwind CSS 4, HTML5 Canvas, IndexedDB, localStorage, lucide-react и gifenc. Тесты используют Node.js node:test, tsx и fake-indexeddb. Браузерные проверки дополнительно используют Playwright.
Нужны Node.js 22+ и npm. Используется package-lock.json.
npm install
npm run devПо умолчанию Vite слушает порт 3000. Для воспроизводимого запуска на свободном порту:
npm run dev -- --port 3017 --strictPortПроверки:
npm run lint
npm test
npm run build
npm run previewlint запускает TypeScript без генерации файлов, с проверкой неиспользуемых импортов и параметров. Отдельного ESLint-скрипта нет. build создаёт production-файлы в dist/.
Запустите dev-сервер, затем npm run test:browser. Тесты используют новый временный профиль Chrome с отдельными IndexedDB и localStorage; реальные пользовательские данные не затрагиваются.
Для этого нужен доступный модуль Playwright и установленный Google Chrome. Playwright не добавлен в обязательные зависимости приложения. Если он предоставлен окружением, укажите абсолютный путь к модулю через PLAYWRIGHT_MODULE_PATH; иначе его можно установить отдельно для локальной проверки (npm install --no-save --package-lock=false playwright).
Пример PowerShell:
$env:PLAYWRIGHT_MODULE_PATH = '<путь к модулю playwright>'
$env:TEST_ORIGIN = 'http://127.0.0.1:3017'
$env:TEST_PRODUCTION_ORIGIN = 'http://127.0.0.1:3018'
$env:TEST_BROWSER_CHANNEL = 'chrome'
$env:TEST_SCREENSHOTS = '<папка вне исходного кода для PNG>'
npm run test:browserTEST_ORIGIN по умолчанию равен http://localhost:3000. TEST_SCREENSHOTS необязателен. Тесты проверяют интерфейс, инструменты, реальные скачивания PNG/GIF, миграцию, ошибку сохранения и размеры 320×700, 390×844, 768×1024, 1180×820, 1440×900 и 1920×1080. Они обращаются к исходным модулям Vite для подготовки изолированных данных, поэтому должны запускаться против dev-сервера.
Для отдельной проверки собранной версии запустите npm run preview -- --host 127.0.0.1 --port 3018 --strictPort и укажите TEST_PRODUCTION_ORIGIN. Эта проверка использует отдельный временный профиль, рисует, сохраняет, полностью закрывает Chrome и повторно открывает его, проверяет восстановление рисунка и GIF-экспорт. Если переменная не задана, эта проверка помечается как пропущенная. Сенсорный ввод проверяется дополнительно в эмулированном мобильном контексте Chrome.
src/App.tsx: навигация между библиотекой и редактором; редактор получает отдельное начальное состояние и пересоздаётся при смене проекта.src/components/HomeScreen.tsx,ProjectCard.tsx,ProjectModals.tsx: библиотека проектов, меню и окна управления.src/domain/project.ts: схема версии 2, валидация, идентификаторы, независимые копии и перенос старых кадров.src/services/projectRepository.ts: CRUD, атомарные транзакции IndexedDB, получение карточек и проверяемая миграция.src/domain/projectSaveSession.ts,src/hooks/useProjectPersistence.ts: снимки изменений, последовательная очередь записи, автосохранение и сохранение перед выходом.src/domain/history.ts,src/hooks/useFrameHistory.ts: неизменяемые снимки кадров, ветвление Undo/Redo и ограничение истории до 50 записей.src/hooks/useFrames.ts: операции кадров, импорт, вывод на холст и экспорт.src/canvas/frameRenderer.ts,rasterSelection.ts: композиция изображений и объектов, кэш слоёв, вырезание и перемещение рисунков без дублирования исходного места.src/domain/transaction.ts: фиксация незавершённых операций текста и стикеров.scripts/test-*.ts: тесты модели, истории, репозитория, сохранения и регрессий;scripts/test-browser.cjs: поведенческий браузерный аудит.
Проект хранит стабильный ID, название, даты создания/изменения, кадры, выбранный кадр и скорость. Кадр содержит ID, PNG-основу, объекты текста/стикеров/растровых слоёв и составное PNG-превью. Копирование создаёт новые ID проекта, кадров и объектов, сохраняя независимое содержимое.
Рисунки находятся в IndexedDB: база multipulti, версия 1, хранилище projects, отдельная запись на каждый ID. Ключ current оставлен для совместимости со старой однопроектной версией и содержит последнюю сохранённую копию. Он не заменяет записи независимых проектов.
Настройки палитры находятся в localStorage под ключом multipulti_preferences. Старое состояние multipulti_state переносится в проект версии 2.
При запуске старая запись только под current получает отдельный ID и проверяется чтением. Отличающийся старый документ из localStorage переносится отдельным проектом. Исходный localStorage удаляется только после успешной записи, повторного чтения, сравнения и сохранения настроек. Если источник изменился во время переноса, новая исходная запись остаётся нетронутой. Неуспешную миграцию можно повторить; одновременно начатые вызовы в одной вкладке используют общую операцию.
Нераспознанные записи не удаляются автоматически. Повреждённая карточка показывает сообщение, а остальные проекты остаются доступны. Ошибка открытия не запускает сохранение пустого документа поверх исходных данных. При замене current другой проект сохраняет старую отдельную запись, включая ранее осиротевший источник.
Изменения зафиксированных кадров, скорости и выбора кадра запускают запись через 600 мс после последнего изменения. Воспроизведение не записывает каждый показанный кадр. Очередь сериализует записи и сохраняет снимок конкретного проекта; ошибка не останавливает следующие попытки.
При нажатии «Мультики» редактор ждёт текущий импорт, фиксирует незавершённые действия текста/стикера/выделения и завершает запись до перехода. При ошибке редактор остаётся открыт, изменения остаются в памяти и показывается сообщение. Повторное нажатие выполняет новую попытку.
При скрытии страницы приложение пытается сохранить доступные изменения. Перед обычным закрытием/перезагрузкой браузер получает предупреждение, если есть несохранённые изменения или незавершённое действие. Браузер может не показать его без предварительного взаимодействия пользователя.
Undo/Redo работает в текущей сессии редактора. После повторного открытия восстанавливается сохранённое содержимое, а история начинается заново. Незавершённый ввод текста фиксируется при подтверждении, смене инструмента/кадра, скрытии страницы или выходе на главный экран.
- Данные привязаны к браузерному профилю и origin (протокол, адрес и порт).
localhostи127.0.0.1, а также разные порты имеют разное хранилище. - Нет облачной синхронизации и автоматических резервных копий. Очистка данных сайта, удаление профиля, приватный режим и ограничения квоты могут удалить или сделать недоступными локальные проекты.
- Асинхронная запись не гарантирует сохранения последних действий при аварии браузера, отключении питания или принудительном завершении процесса.
- Одновременное редактирование одного проекта в нескольких вкладках не имеет системы разрешения конфликтов; последняя успешная запись может заменить изменения другой вкладки. Для такого сценария используйте одну вкладку редактора.
- Импорт ограничен 15 МБ и разрешением 8192×8192. Проверка разрешения происходит после декодирования браузером. Большие изображения вписываются в холст 800×600.
- GIF имеет ограниченную палитру. Экспорт не переносит редактируемые объекты, историю и все настройки проекта в другой браузер.
- Производительность и квота зависят от устройства и содержимого кадров. Нагрузочные проверки небольших изображений не доказывают отсутствие проблем с сотнями полноразмерных фотографий.
- Основной браузерный аудит выполнен в Chrome на Windows с эмуляцией размеров окна. Реальные Safari/Firefox, мобильные устройства и стилусы отдельно не проверялись.
- Дополнительные шрифты загружаются с Google Fonts; без сети используется системный запасной шрифт. В автоматических тестах внешняя загрузка шрифтов отключена для воспроизводимости.
Подробные исправления и границы проверки перечислены в итоговом отчёте чата. Обязательные локальные команды выполняются перед передачей результата; приложение не публикуется и удалённый репозиторий не изменяется.