
До момента, когда я сел писать эту статью, я вообще не понимал, что такое тамагочи. Нет, не в смысле «никогда не слышал» — конечно, слышал и видел (не вживую, через экран). Где-то на уровне культурного шума это слово всплывало регулярно в американских фильмах или сериалах, где герой с придыханием вспоминает игрушку детства и рассказывает, как ему это нравилось. Ярче всего у меня в памяти отпечаталась сцена из знаменитого детективного сериала «Менталист»: Патрик Джейн с неизменной полуулыбкой вручает коллеге тамагочи, и тот, взрослый серьёзный мужик (не очень серьёзный на вид, но в момент моего просмотра все взрослые люди серьёзные), вдруг расплывается: «О боже, у меня в детстве такой был! Я их обожал! Как ты узнал!» и т. д.
Раньше я реагировал на такие моменты как на упоминание Game Boy или Dendy: «ну да, старая штука, скорее всего, что-то похожее на Game Boy, который мне был понятен на то время», и я думал: «кому-то дорога как воспоминание, но мне-то чего с того, игрушка есть игрушка». Но сейчас в какой-то момент мне стало понятно, что если об этой игрушке говорят до сих пор, если она пережила три десятилетия и кучу переосмыслений — значит, там внутри что-то большее, и надо посмотреть, что это и как работает.
Так я и сделал. И для начала — немного истории, потому что без неё нет смысла вспоминать и описывать старые вещи (всё, что больше 10 лет назад, уже старое, поэтому, надеюсь, без обид xd).

Компания Bandai выпустила оригинальный тамагочи в 1996 году. Придумали его Аки Маита и Акихиро Йокои. Формула, как я уже знал к тому моменту, была убийственно проста: яйцо → детёныш → взрослый → старый. Несколько шкал — голод, счастье, здоровье — которые монотонно убывают, и кнопки, чтобы их восполнять. Не покормил, не поиграл, не уложил спать — умирает. Звучит примитивно. Но весь мой скепсис по поводу «ну подумаешь, три полоски» разбился о цифру: только за первый год продаж — несколько десятков миллионов штук. Десятков миллионов. С тремя кнопками и монохромным экраном.
К моменту, когда я уже начал писать код, меня не отпускала параллель с другой игрой, гораздо более современной, но построенной ровно на том же фундаменте: «Мой Говорящий Том». Думаю, многие об этой игре хотя бы слышали. Виртуальный кот, которого можно кормить, гладить, укладывать спать и которому на тебя, по большому счёту, плевать — но ты всё равно возвращаешься. Тот же цикл заботы, тот же примитивный интерфейс, те же эмоции. Тамагочи, получается, изобрёл эту формулу ещё до того, как мобильные игры вообще появились. И вот с этим пониманием — примерно как должна выглядеть игра — я и начал писать собственный симулятор, просто чтобы посмотреть, как это выглядит.
Интересные тамагочи, который нашёл.
Немного в сторонку, увидел «Bandai готовит к выпуску тамагочи с Дартом Вейдером», когда искал информацию, и считаю, что надо такое же сделать, только онлайн.

Основная часть
Что я решил поменять
Взять формулу из девяносто шестого года и просто перерисовать её — нет, это было бы скучно, ну, скорее, даже не скучно, а нелогично, мне же нужно просто потыкать и посмотреть, как это работает, и основную логику скопировать. Хотел сохранить узнаваемость, но добавить слой.
Первое и самое важное: я не знаю, кто вылупится из яйца. Буквально. Яйцо у всех одинаковое, а дальше — рулетка. Цыплёнок, котёнок, щенок, дракончик, медвежонок или крольчонок — решает генератор случайных чисел в момент старта. Никаких подсказок, никаких намёков. Игрок узнает, кто у него, только когда яйцо треснет. Мне хотелось воссоздать то чувство, которое, судя по всему, испытывали дети в девяностые: ты включаешь игрушку и понятия не имеешь, кто там внутри. Маленький, но честный сюрприз.
Второе — коллекция. Есть отдельная панель «Питомцы» со всеми шестью видами, но пока вы конкретный вид не встретили лично — там висит «???». Открытие запоминается на устройстве навсегда и живёт отдельно от текущего питомца. Умер ваш тамагочи? Начали заново? Коллекция никуда не денется. А когда соберётся полный комплект — панель окрашивается в золото и на пару секунд играет короткая победная тема. Мелочь, но я заметил, что именно эта мелочь заставляет возвращаться к игре даже после нескольких смертей подряд.
if (result.justCompleted) { Tama.playVictorySound(); }
Третье — случайные события. В оригинале всё держалось исключительно на действиях игрока: не нажал кнопку — шкала упала, нажал — поднялась. Механически честно, но эмоционально плоско и скучно. Я добавил жизнь, которая происходит сама по себе (да, там тоже зацикленные события, но хотя бы так интереснее): дождь — значит, падает настроение, кошмар отнимает сон, иногда питомец находит подарок. А отдельным событием — питомец сам «хочет поиграть», и если в этот момент зайти в мини-игру, награда удваивается. Это единственный способ получить x2, нужно ловить момент, как в жизни с ребёнком.
Четвёртое — мини-игра. Выбор пал на камень-ножницы-бумага, простая игра, и думать не надо, как её добавлять в тамагочи. Механически то же самое: тратим немного шкалы сна, получаем случайную награду радости.
Ну и до кучи — кнопка ускорения времени, потому что ждать тридцать секунд до следующего игрового дня, когда ты отлаживаешь механику, — то ещё испытание. И панели правил и галереи можно перетаскивать мышкой. Потому что тоже во время проверок мешает, и думаешь, куда это убрать.
Структура проекта
Никаких сборщиков, фреймворков, npm и node_modules, просто HTML, CSS и набор подключаемых <script>, в теории как обычно в моих статьях. Но в этот раз я сознательно дробил логику мельче, чем обычно себе позволяю. Не ради производительности — ради здравого смысла.
tamagotchi/ ├── index.html ├── css/ │ └── style.css └── js/ ├── constants.js ├── audio.js ├── state.js ├── sprites.js ├── collection.js ├── ui.js ├── events.js ├── minigame.js ├── drag.js └── main.js
Каждый файл отвечает ровно за одну вещь. constants.js хранит тайминги и характеристики видов. audio.js — три функции для Web Audio API: звук без единого mp3-файла (чтобы не было проблем). state.js — единственный источник правды о питомце и его сохранение в localStorage. sprites.js рисует питомца на canvas. collection.js — отдельная память устройства про то, кого вы уже видели. ui.js перекладывает состояние в DOM. events.js и minigame.js — две самодостаточные механики. drag.js — перетаскивание панелей. main.js всё это связывает и крутит игровой цикл.
Самое ценное в таком дроблении — не архитектурная чистота, а то, что когда на середине проекта я решил переделать мини-игру, я трогал только minigame.js. Когда посыпались баги с отображением эмоций — только ui.js. Ничего не расползалось. В голове держишь не весь проект целиком, а один файл. Для веб-проекта, который делаешь вечерами, это спасает.
Как стареет и умирает питомец
Стадия жизни — это не отдельный таймер, а прямой вывод из возраста в секундах. Яйцо, детёныш, взрослый и старый — просто разные диапазоны одной величины:
function getStage(ageSeconds) { if (ageSeconds >= STAGE_AGE_SECONDS.old) return STAGE_OLD; if (ageSeconds >= STAGE_AGE_SECONDS.adult) return STAGE_ADULT; if (ageSeconds >= STAGE_AGE_SECONDS.baby) return STAGE_BABY; return STAGE_EGG; }
Каждые пять секунд шкалы голода, сна и счастья слегка проседают. Здоровье устроено интереснее: само по себе оно почти не падает. Но как только любая из трёх шкал касается нуля — здоровье начинает сыпаться дополнительным штрафом. Смерть здесь — это не «забыл покормить один раз», а стабильное пренебрежение в течение нескольких минут. Мне важно было, чтобы игрок не мог убить питомца одним пропущенным действием, но и совсем расслабиться тоже не мог. Примерно как с настоящим домашним животным: один день без еды — плохо, но не смертельно. Неделя — уже всё.
Как я рисовал питомца без единой картинки
Вот здесь началось самое интересное. Изначально я попробовал обойтись эмодзи. Быстро, дёшево и выглядит так, будто рисовал трёхлетний ребёнок. Без обид в сторону детей — просто эмодзи не предназначены для того, чтобы их растягивать на весь экран и пытаться выразить ими десяток эмоций. Пришлось рисовать самому (кодом, т. к. я не художник и мои рисунки будут хуже трёхлетнего ребёнка).

Тело, уши и мордочка — это фигуры, собранные построчно прямо на canvas. Закрашенный круг — просто набор горизонтальных отрезков переменной ширины, посчитанных через Теорему Пифагора для каждой строки:
function fillCircle(ctx, cx, cy, r, color) { ctx.fillStyle = color; for (let y = -r; y <= r; y++) { const dx = Math.round(Math.sqrt(Math.max(0, r * r - y * y))); ctx.fillRect(cx - dx, cy + y, dx * 2, 1); } }
Из таких же отрезков собраны уши, пятна и блик. Никаких загруженных спрайтов — только математика.
Но самое приятное открытие — это контур. Без обводки любой пиксель-арт выглядит так, будто его вырезали ножницами из цветной бумаги и приклеили на фон. Рисовать обводку вручную для каждой фигуры — ушей, которые бывают шести разных форм, пятен, бликов — означало бы утроить объём кода и поседеть раньше времени.
Вместо этого я пошёл на хитрость. Питомец рисуется дважды. Сначала — во временный, невидимый canvas. Затем я беру этот результат и через globalCompositeOperation = 'source-in' перекрашиваю все непрозрачные пиксели в один тёмный цвет. Получается силуэт. А дальше — магия: я штампую этот силуэт восемь раз вокруг нужной позиции со сдвигом в один пиксель по каждому направлению. Вверх, вниз, по диагоналям. Поверх всего этого рисую оригинал без сдвига. Получается ровная, чёткая обводка, которая одинаково хорошо работает для головы, ушей и даже маленького пятнышка на щеке.
const outline = makeOutlineLayer(buf, '#2b1d14'); [ [-1, 0], [1, 0], [0, -1], [0, 1], [-1, -1], [1, -1], [-1, 1], [1, 1] ].forEach(([dx, dy]) => { mainCtx.drawImage(outline, dx, dy); }); mainCtx.drawImage(buf, 0, 0);
Добавил полупрозрачный белый блик на макушке и маленькую точку в каждом глазу — и питомец внезапно перестал быть набором геометрических фигур. Он стал похож на наклейку. Дешёвый трюк, а разница в восприятии — колоссальная.
Настроения я тоже рисую, а не беру готовыми. Закрытые глаза и плавающая буква «Z» для сна. Перечёркнутые крестиком глаза для смерти. Красный крестик-пластырь на макушке для болезни. Слеза для грусти. И всё это привязано к реальным показателям: грустный питомец не потому, что мне так захотелось, а потому что шкала счастья действительно провалилась ниже порога. Эмоция — следствие состояния, а не декорация.
Заключение
Начиналось всё с вопроса: «Почему все так носятся с этой игрушкой тридцатилетней давности?» А закончилось тем, что я два вечера разбирался, как штамповать силуэты на canvas ради обводки в один пиксель. И знаете — оно того стоило.


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

Из того, что оставил на потом: анимацию самого перехода между стадиями. Сейчас питомец просто меняется на следующем рендере, без плавности. Хочется добавить эффект превращения — трещины на яйце, вспышку, что-то такое. И, возможно, больше видов в коллекции. Шесть — это только начало.
А параллель с «Говорящим Томом», с которой всё началось, в итоге оказалась точнее, чем я думал. Это действительно один и тот же архетип — цифровое существо, которому нужна твоя забота. Только тамагочи изобрёл его в девяносто шестом, с тремя кнопками и монохромным экраном. А спустя почти тридцать лет я сидел и писал его на JavaScript.
Код проекта лежит в репозитории, ссылка:
P. S. Если найдёте баг, придумаете седьмой вид питомца или есть какие-то замечания — пишите в комментариях.
© 2026 ООО «МТ ФИНАНС»
Комментарии (6)

domix32
13.07.2026 11:00Как-то странно себя сон ведёт - плохо восполняется, быстро тратится.
У довольного цыплёнка над головой вист какой-то непонятный хвостик слева над головой
Скрытый текст

Ещё бы предложил сделать так чтобы панель с ачивками была также рядом на странице, а не требовала необходимость крутить страницу, а раздел с помощью вообще спрятать под какую-нибудь кнопку.
Ну, а новых видов придумать вроде не сложно - бычок, лама, капибара, аксолотль, коза, слоник, бабуин, ёжик,
крош, совунья, попугай и тп.
wii
Чтобы не переживать за питомца, подключил автоматическую следилку за его состоянием дел. Теперь мой питомец всегда выспавшийся, сытый, здоровый и веселый :)
Скрипт для консоли
Laborant_Code Автор
Хороший вариант, но как говорится: читы — бан, кемперство — бан, автоматизация заботы о питомце — удаление и потом бан. Всем удачи!
wii
“И питомцы целы, и читы слиты” – старая предбановская поговорка :) Спасибо!