Экспорт, GIF и публикация

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

saveCanvas() — команда p5.js, которая сохраняет текущий кадр холста в файл-картинку на твоём компьютере.

Зачем вообще что-то экспортировать

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

Обидно, правда? Ты не можешь поставить такую работу на аватарку в Telegram, не можешь скинуть другу в личку, не можешь выложить в сторис «смотрите, что я закодил». Картинка есть на экране, но её как будто и нет: она нарисована заново каждый кадр и нигде не хранится файлом.

Этот урок — про то, как достать работу из браузера в реальный мир. Мы научимся трём вещам: сохранять кадр картинкой (как скриншот, только чистый, без рамок браузера), записывать короткий GIF (зацикленную анимацию, которую любят мессенджеры и соцсети) и публиковать скетч онлайн по ссылке, чтобы любой человек открыл твоего живого цыплёнка прямо в браузере. К концу урока у тебя на руках будет картинка, гифка и ссылка — полный набор, чтобы показать миру CodeChick.

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

Картинка, гифка и ссылка — три разных «сувенира»

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

СпособЧто получаешьКогда брать
Картинка (PNG)Один застывший кадрАватарка, обложка, постер
GIFКороткая зацикленная анимацияСторис, стикер, демо движения
Публикация (ссылка)Живой скетч в браузереПоказать интерактив, портфолио

Картинка — самый лёгкий и универсальный сувенир. GIF показывает движение, но весит больше и обычно короткий — пара секунд. А ссылка — единственный способ передать интерактив: если твой цыплёнок бегает за мышкой, в картинке и гифке этого не покажешь, а по ссылке друг сам подвигает курсор и всё увидит.

Картинка — это фотка момента. GIF — короткое видео без звука. Ссылка — живая трансляция, где зритель сам управляет.

Разбираем на примерах

Пример 1. Сохраняем кадр через saveCanvas()

Самый частый запрос: «хочу просто красивую картинку моего цыплёнка». Для этого есть команда saveCanvas(). Она берёт текущее содержимое холста и кладёт его в файл на компьютере — чисто, без рамок браузера и без курсора, в отличие от обычного скриншота кнопкой Print Screen.

function setup() {
  createCanvas(400, 400);
  noStroke();
}

function draw() {
  background(255, 180, 120); // тёплый закат
  fill(255, 221, 51);        // жёлтое тело
  circle(200, 240, 120);
  circle(200, 150, 80);      // голова
  fill(255, 140, 0);
  triangle(200, 150, 230, 165, 200, 175); // клюв
}

function keyPressed() {
  if (key === 's') {
    saveCanvas('codechick', 'png'); // нажми S — скачается codechick.png
  }
}

Результат: на экране цыплёнок на закатном фоне. Пока ты ничего не нажимаешь — просто картинка. Как только ты жмёшь клавишу S, браузер скачивает файл codechick.png с ровно этим кадром, без рамок и курсора.

Разберём по строчкам. Рисование тела и головы тебе уже знакомо с первых уроков. Главное здесь — функция keyPressed(): это специальная функция p5.js, которую библиотека вызывает каждый раз, когда ты нажимаешь любую клавишу. Внутри мы проверяем условием if (key === 's'), что нажата именно буква S. Если да — выполняется saveCanvas('codechick', 'png'). Первый аргумент — имя файла (без точки и расширения), второй — формат: 'png' для картинки с прозрачностью или 'jpg' для фотографий.

Почему мы повесили сохранение на клавишу, а не просто написали saveCanvas() внутри draw()? Потому что draw() повторяется десятки раз в секунду — и если сохранять в нём, браузер за секунду попытается скачать тебе полсотни файлов и захлебнётся. Сохранять нужно по событию: один раз, когда ты сам решил. Нажатие клавиши — идеальный момент.

Маленькая, но важная деталь про размер картинки. Файл сохранится ровно в том разрешении, в котором создан холст: createCanvas(400, 400) даст картинку 400 на 400 точек. Для аватарки в мессенджере этого хватит, а вот для постера на стену или обложки альбома 400 пикселей — маловато, картинка будет мыльной при увеличении. Хочешь крупнее и резче — просто задай холст побольше, например createCanvas(1080, 1080) (популярный квадрат для соцсетей), и пересчитай координаты фигур под новый размер. Правило простое: какой холст — такая и картинка, p5.js ничего не дорисовывает за тебя.

И ещё про форматы. 'png' хорош тем, что умеет хранить прозрачность: если у тебя фон не залит, вокруг цыплёнка будет прозрачная область, и его удобно вставлять на любой цвет. 'jpg' прозрачности не умеет и слегка «съедает» резкие края, зато даёт файл поменьше — он создан для фотографий, а не для графики с чёткими линиями. Для рисунков кодом почти всегда бери 'png': цыплёнок останется чётким, а края — ровными.

Пример 2. Сохраняем именно тот кадр, который понравился

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

let y = 0;
let paused = false;

function setup() {
  createCanvas(400, 400);
  noStroke();
}

function draw() {
  background(135, 206, 235);
  if (!paused) {
    y = y + 2;           // цыплёнок падает вниз
    if (y > 300) y = 0; // и снова прыгает наверх
  }
  fill(255, 221, 51);
  circle(200, y, 80); // тело движется по Y
}

function keyPressed() {
  if (key === ' ') {
    paused = !paused; // пробел — пауза/продолжить
  }
  if (key === 's') {
    saveCanvas('codechick-frame', 'png');
  }
}

Результат: цыплёнок падает сверху вниз и перепрыгивает обратно наверх по кругу. Нажимаешь пробел — движение замирает на текущем кадре. Спокойно жмёшь S — скачивается codechick-frame.png с той позицией, которую ты выбрал. Ещё раз пробел — анимация снова поехала.

Тут работает переменная состояния paused: она хранит между кадрами, стоим мы на паузе или нет. Строка paused = !paused — это переключатель: знак ! означает «наоборот», поэтому каждое нажатие пробела меняет true на false и обратно, как кнопка света. Пока paused равно true, условие if (!paused) не выполняется, и координата y не меняется — кадр застывает. Очень удобно для охоты за идеальным моментом.

Заметь тонкость: на паузе мы перестаём двигать цыплёнка, но draw() всё равно крутится и продолжает перерисовывать кадр — просто с одними и теми же числами. Поэтому холст не гаснет и не зависает, картинка остаётся живой, ты её спокойно рассматриваешь. Это другой подход, чем команда noLoop(), которая вообще останавливает draw(): с ней холст замораживается жёстко, и потом сложнее снова всё запустить. Для нашей задачи «замри — сохрани — поехали дальше» переключатель-флаг гибче и понятнее. Кстати, на пробел мы повесили паузу не случайно: в плеерах и играх пробел почти всегда значит «пауза/продолжить», так что твой скетч сразу ощущается привычно.

Пример 3. Записываем короткий GIF

Картинка — это здорово, но движение цыплёнка хочется показать в движении. Тут выручает GIF — зацикленная анимация без звука, родной формат мемов и стикеров. В свежих версиях p5.js есть готовая команда saveGif(): ты говоришь, как назвать файл и сколько секунд записывать, а библиотека сама склеит кадры в гифку.

let angle = 0;

function setup() {
  createCanvas(400, 400);
  noStroke();
}

function draw() {
  background(135, 206, 235);
  fill(255, 221, 51);
  push();
  translate(200, 200); // центр холста
  rotate(angle);        // вращаем систему координат
  circle(0, 60, 40);    // цыплёнок кружит вокруг центра
  pop();
  angle = angle + 0.05; // каждый кадр чуть-чуть поворачиваем
}

function keyPressed() {
  if (key === 'g') {
    saveGif('codechick-loop', 3); // нажми G — запишется 3 секунды GIF
  }
}

Результат: жёлтый цыплёнок по кругу облетает центр холста на голубом фоне. Когда ты нажимаешь клавишу G, p5.js пару секунд молча записывает анимацию, а затем скачивает файл codechick-loop.gif — зацикленную гифку, где цыплёнок бесконечно нарезает круги.

Разберём ключевое. saveGif('codechick-loop', 3) принимает имя файла и длительность в секундах — здесь 3. Записывать стоит коротко: гифка на 10 секунд весит очень много и грузится медленно, а зацикленные 2–4 секунды выглядят аккуратно и легко расходятся по мессенджерам. Чтобы петля смотрелась бесшовно, движение лучше делать таким, чтобы конец совпадал с началом — например, полный оборот по кругу, как здесь с rotate.

Обрати внимание на пару push() / pop() вокруг трансформаций: push() запоминает систему координат, мы её сдвигаем и крутим, рисуем цыплёнка, а pop() возвращает всё обратно — чтобы поворот не накапливался на других фигурах. Это та самая защита настроек, которую ты проходил в уроке про трансформации.

Пара слов о том, что происходит «под капотом» при записи. Команда saveGif() не снимает экран в реальном времени, как видеозапись игры. Она работает умнее: на несколько секунд берёт управление и быстро прогоняет твой draw() кадр за кадром, складывая каждый кадр в стопку, а потом склеивает их в один зацикленный файл. Поэтому во время записи скетч может на мгновение «задуматься» и не реагировать на мышь — это нормально, библиотека просто занята сборкой гифки. Дождись, пока файл скачается, и всё снова оживёт.

Если в твоей версии p5.js команды saveGif() вдруг не оказалось (в совсем старых сборках её ещё не было), не расстраивайся: GIF всегда можно записать и сторонними способами — например, бесплатным экранным рекордером, который снимает кусочек экрана в гифку. Но если редактор свежий, проще и чище всё-таки родная saveGif(): она снимает именно холст, без лишних краёв и в точном размере.

Пример 4. Публикуем скетч в онлайн-редакторе

Картинку и гифку ты уже умеешь скачивать. Но самый эффектный способ поделиться интерактивным цыплёнком — дать ссылку на живой скетч. Тут код почти не нужен: публикация делается не командой, а через сервис. Самый простой — официальный p5.js Web Editor (editor.p5js.org), где ты, скорее всего, и писал свои скетчи.

Порядок такой:

  1. Зайди в аккаунт на editor.p5js.org (регистрация бесплатная, можно через почту).
  2. Открой свой скетч и нажми Save — скетч сохранится в облаке, привязанный к твоему аккаунту.
  3. Нажми кнопку Share. Редактор даст три ссылки: Present (только картинка-результат на весь экран), Edit (открыть с кодом) и Embed (вставить на сайт).
  4. Скопируй ссылку Present и кидай другу — он откроет твоего живого цыплёнка прямо в браузере, ничего не устанавливая.

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

Кроме официального редактора есть и другие площадки: OpenProcessing (галерея творческого кода, где работы лайкают и форкают, как посты), CodePen (универсальная песочница для веб-кода) и GitHub Pages (если хочешь выложить как настоящую страницу со своим адресом). Для старта хватает p5.js Web Editor — остальное освоишь, когда захочешь собрать портфолио.

Зачем вообще нужна ссылка Embed, которую мы пока отложили? Она пригодится, когда у тебя появится свой сайт, блог или страница в школьном проекте: Embed позволяет вставить живой скетч прямо в чужую страницу, как вставляют ролик с видеохостинга. Посетитель твоего сайта увидит работающего цыплёнка, не уходя никуда. Для подростка это звучит далеко, но запомни, что такая возможность есть — однажды захочется собрать портфолио на собственной страничке, и тогда Embed окажется ровно тем, что нужно.

И последнее про этикет публикации. Когда выкладываешь работу на площадку вроде OpenProcessing, по-доброму подписать её: дать название, пару слов, что это и как с ней взаимодействовать («двигай мышкой», «нажми пробел»). Зрителю гораздо приятнее, когда понятно, что перед ним и что можно потрогать. А если ты вдохновлялся чьим-то чужим скетчем или взял кусок кода из примера — упомяни автора. В сообществе творческого кода так принято, и это та мелочь, которая отличает уважительного автора от того, кто просто копипастит.

Частые ошибки и подводные камни

На экспорте новички спотыкаются почти одинаково. Пробеги глазами заранее — сбережёшь нервы.

  • Вызывать saveCanvas() прямо в draw(). Поскольку draw() крутится десятки раз в секунду, браузер попытается скачать тебе лавину файлов и подвиснет. Всегда вешай сохранение на событие — нажатие клавиши в keyPressed() или клик мыши.
  • Делать слишком длинный GIF. Гифка на 8–10 секунд весит десятки мегабайт, медленно записывается и тормозит при отправке. Держись 2–4 секунд и зацикливай движение, чтобы конец совпадал с началом.
  • Путать скриншот и saveCanvas. Кнопка Print Screen снимает весь экран с рамками браузера и курсором. saveCanvas() сохраняет только чистый холст в точном разрешении — для аватарки и постера это намного лучше.
  • Делиться ссылкой Edit вместо Present для готовой работы. Ссылка Edit открывает код и редактор — друг увидит «кухню», а не результат. Для показа бери Present: чистый скетч на весь экран.
  • Забыть нажать Save перед Share. Если скетч не сохранён в облаке, ссылка либо не появится, либо будет вести на пустой проект. Сначала Save, потом Share — порядок важен.
  • Ждать кнопку «Запустить» в наших уроках. Напомним: p5.js работает с холстом в браузере и в учебном раннере не исполняется. Код здесь мы читаем и представляем по описанию, а запускаешь и экспортируешь ты в настоящем редакторе p5.js.

Мини-практика: собери набор «сувениров» CodeChick

Возьми свой генеративный аватар из прошлого урока (или любой скетч с цыплёнком) и доведи его до публикации. Сделай по шагам:

  1. Добавь в скетч функцию keyPressed() с сохранением по клавише S через saveCanvas('moy-codechick', 'png'). Поймай красивый кадр и скачай картинку.
  2. Если аватар анимированный, добавь паузу на пробел (как в примере 2), застынь на лучшем моменте и сохрани именно его.
  3. Запиши короткий GIF на 3 секунды через saveGif('codechick-loop', 3) по клавише G. Постарайся, чтобы движение зацикливалось без рывка.
  4. Сохрани скетч в p5.js Web Editor, нажми Share и скопируй ссылку Present. Отправь её другу или выложи в сторис.

Цель — чтобы у тебя на руках оказались три формата одной работы: картинка, гифка и ссылка. Это и есть мини-портфолио из одного цыплёнка. Попробуй угадать заранее, какой формат друзья оценят больше — а потом проверь на практике.

Итоги

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

  • saveCanvas('имя', 'png') сохраняет текущий кадр чистой картинкой — вешай его на нажатие клавиши, а не в draw().
  • Пауза через переменную состояния помогает поймать и сохранить именно тот кадр анимации, который понравился.
  • saveGif('имя', секунды) записывает короткую зацикленную анимацию — держи её на 2–4 секунды и делай движение бесшовным.
  • Публикация в p5.js Web Editor через Save → Share → ссылку Present даёт живой интерактивный скетч, который друг откроет в браузере без установки.
  • Картинка — для статики, GIF — для движения, ссылка — для интерактива. Выбирай сувенир под задачу.

Твой цыплёнок прошёл путь от одинокой точки в первом уроке до генеративного аватара, который теперь можно скачать, зациклить и выложить в сеть. В следующем уроке мы поговорим о том, как собрать из своих скетчей настоящее портфолио и оформить страницу с работами — чтобы CodeChick стал визитной карточкой твоего творческого кода. Бери лучшие кадры с собой.

Проверьте себя
1. Почему saveCanvas() нельзя вызывать прямо внутри draw()?
AsaveCanvas() работает только в setup()
Bdraw() повторяется десятки раз в секунду, и браузер попытается скачать лавину файлов
CsaveCanvas() портит холст и стирает рисунок
DВ draw() запрещено вызывать любые команды сохранения
2. Что делают первый и второй аргументы в saveCanvas('codechick', 'png')?
AШирину и высоту картинки
BИмя файла и его формат (расширение)
CКоординаты X и Y, откуда начать сохранение
DКачество и прозрачность
3. Какой формат выбрать, чтобы показать ДВИЖЕНИЕ цыплёнка коротким зацикленным роликом без звука?
APNG-картинку через saveCanvas()
BGIF через saveGif()
CСсылку Edit из редактора
DСкриншот кнопкой Print Screen
4. Почему длительность GIF стоит держать в районе 2–4 секунд?
AДлиннее p5.js просто не умеет записывать
BДолгая гифка весит десятки мегабайт, медленно записывается и тормозит при отправке
CКороткие гифки качественнее по цвету
DЭто требование редактора p5.js Web Editor
5. Какую ссылку из кнопки Share лучше дать другу, чтобы он увидел ГОТОВЫЙ скетч на весь экран, а не код?
AEdit
BEmbed
CPresent
DЛюбую — разницы нет
6. В чём главное преимущество публикации скетча по ссылке перед картинкой или GIF?
AСсылка весит меньше всех других форматов
BПо ссылке скетч реально исполняется, и зритель может сам взаимодействовать с интерактивом (мышь, клавиши)
CСсылку нельзя случайно удалить
DКартинку и GIF вообще нельзя никому отправить