
Карта мира за 500 байт: магия сжатия и JavaScript
Как уместить ASCII-карту всего мира в 445 байт данных? Разбираем трюк с deflate-сжатием и fetch() в браузере без единой библиотеки.
Карта мира за 500 байт: магия deflate-сжатия и нативного JavaScript
Что, если я скажу вам, что полноценную ASCII-карту всего мира — со всеми континентами и океанами — можно уместить буквально в несколько сотен байт? Именно это сделал разработчик Иво Кадзела (Iwo Kadziela) при помощи ИИ-ассистента OpenAI Codex. Результат — карта, которая занимает 445 байт сжатых данных и разворачивается прямо в браузере с помощью нескольких строк чистого JavaScript — без каких-либо сторонних библиотек.
Это не просто забавный трюк. Это отличная демонстрация того, насколько мощными могут быть современные браузерные API в сочетании с классическими алгоритмами сжатия.
Что такое DEFLATE и почему он такой эффективный?
DEFLATE — это формат сжатия данных без потерь, который сочетает два хорошо известных метода: словарный алгоритм для устранения избыточности и схему кодирования переменной длины. Формат определён в RFC 1951 и используется в таких популярных инструментах, как gzip и ZIP.
Первая фаза DEFLATE использует вариант алгоритма LZ77: он сканирует входные данные скользящим окном, которое запоминает историю недавних байтов. Когда обнаруживается последовательность байтов, уже встречавшаяся в этом окне, алгоритм записывает пару (смещение, длина), указывающую на более раннее вхождение, вместо того чтобы записывать байты повторно.
После фазы LZ77 поток содержит смесь литеральных байтов и пар длина/расстояние. Следующий шаг — уменьшить энтропию этого потока с помощью префиксного кода. Для этой цели DEFLATE использует кодирование Хаффмана.
Английский текст обычно сжимается в 2,5–3 раза; исполняемые файлы — несколько меньше; графические данные, такие как растровые изображения, могут сжиматься значительно сильнее. Текстовые карты с повторяющимися символами (~ для воды, # или буквы для суши) — идеальный кандидат для этого алгоритма: паттерны крайне регулярны, и DEFLATE «выжимает» их до минимума.
Как это работает: схема проекта
graph TD
A[ASCII-карта мира\n~несколько килобайт текста] --> B[DEFLATE-сжатие\ndeflate-raw]
B --> C[445 байт бинарных данных]
C --> D[Base64-кодирование\nbtoa]
D --> E[Data URI строка\ndata:;base64,...]
E --> F[fetch Data URI\nв браузере]
F --> G[DecompressionStream\ndeflate-raw]
G --> H[Response.text\nраспаковка в строку]
H --> I[Вставка в DOM\nb.innerText]
Весь конвейер умещается в четыре шага:
- Исходная ASCII-карта кодируется и сжимается алгоритмом DEFLATE.
- Сжатые байты преобразуются в строку Base64 (кодировка для хранения двоичных данных в тексте).
- Эта строка вставляется прямо в JavaScript как Data URI — специальный формат
data:;base64,<данные>. - В браузере вызывается
fetch()с этим URI, поток пропускается черезDecompressionStream, и карта появляется на экране.
Ключевой трюк: fetch() с Data URI
Самое неожиданное открытие в этом проекте — возможность передавать Data URI прямо в fetch(). Большинство разработчиков привыкли использовать fetch() для загрузки ресурсов с удалённых серверов, но оказывается, API прекрасно работает и с встроенными данными.
Вот упрощённый вариант кода, который использовался в проекте:
fetch('data:;base64,1ZpLsgIxCEXnrM...==')
.then(r => r.body.pipeThrough(
new DecompressionStream('deflate-raw')
))
.then(s => new Response(s).text())
.then(t => document.getElementById('map').innerText = t);
Разберём каждую строку:
fetch('data:;base64,...')— загружаем Data URI как обычный HTTP-ресурс. Браузер возвращает объектResponseс телом в виде потока байтов..pipeThrough(new DecompressionStream('deflate-raw'))— Compression Streams API позволяет сжимать и распаковывать потоки данных в форматах gzip или deflate (включая deflate-raw) прямо в браузере. Благодаря встроенному сжатию JavaScript-приложениям не нужно включать стороннюю библиотеку сжатия — размер загружаемого приложения остаётся меньше.new Response(s).text()— для преобразования распакованного потока в пригодную для использования строку можно воспользоваться функциейtext()нативного классаResponse.- Наконец, полученный текст вставляется в DOM — и карта готова.
deflate подразумевает формат zlib (с заголовком), а deflate-raw — «голый» DEFLATE-поток без оберток. В данном проекте используется именно deflate-raw, поскольку данные сжаты без zlib-заголовка — это экономит несколько дополнительных байт. Один и тот же алгоритм должен быть указан и при сжатии, и при распаковке.Роль OpenAI Codex в создании проекта
Иво Кадзела создал этот проект в соавторстве с OpenAI Codex — современным ИИ-ассистентом для программирования. Codex — это облачный агент для разработки программного обеспечения, способный выполнять множество задач параллельно: писать функции, отвечать на вопросы о кодовой базе, исправлять ошибки и предлагать pull request-ы для ревью.
Codex работает на базе codex-1 — версии модели OpenAI o3, оптимизированной для задач разработки. Он был обучен с подкреплением на реальных задачах программирования в различных средах, чтобы генерировать код, максимально приближенный к человеческому стилю.
Это показательный пример того, как ИИ-ассистент помогает не просто «написать код», а решить нетривиальную инженерную задачу: выбрать алгоритм, применить нестандартные браузерные API и минимизировать итоговый размер до предела.
«Лучшие инструменты — те, что открывают для вас возможности, о которых вы даже не знали».
Сравнение подходов к хранению карты
| Подход | Размер данных | Нужна библиотека? | Работает в браузере? |
|---|---|---|---|
| Внешний SVG-файл | ~500 КБ+ | Нет | Да |
| Растровое PNG-изображение | ~50–200 КБ | Нет | Да |
| ASCII + gzip + base64 (внешний файл) | ~1–5 КБ | Нет | Да |
| ASCII + deflate-raw + Data URI | ~600 байт | Нет | Да |
| ASCII без сжатия (текст) | ~5–15 КБ | Нет | Да |
Как видно из таблицы, подход с deflate-raw и Data URI даёт экстремально компактный результат — и при этом не требует ни одного внешнего файла или библиотеки. Всё встроено прямо в JavaScript-код.
Почему Base64, а не просто двоичные данные?
Проверенный способ хранить двоичные данные в текстовых файлах — это, конечно, Base64. Однако эта схема способна хранить лишь шесть бит данных на текстовый символ, что даёт рост объёма на 33% (при 8-битной кодировке символов).
Этот overhead — неизбежная плата за возможность встроить двоичные данные прямо в JavaScript-строку или HTML-атрибут. На практике 33% «накладных расходов» с лихвой компенсируются самим deflate-сжатием: ведь 445 байт исходных данных превращаются в ~600 байт Base64, что всё равно несопоставимо меньше оригинального текстового файла карты.
Вы можете воспроизвести этот трюк для любых небольших текстовых данных:
- Сожмите текст через
CompressionStream('deflate-raw')в браузере. - Закодируйте результат в Base64 через
btoa(). - Вставьте строку в
fetch('data:;base64,...'). - Распакуйте обратно через
DecompressionStream('deflate-raw').
Весь процесс — нативный JavaScript, без зависимостей!
Compression Streams API: браузерный инструмент без библиотек
Один из ключевых компонентов этого трюка — Compression Streams API (API потоков сжатия). Это нативный браузерный интерфейс, о котором многие разработчики даже не подозревают.
Compression Streams API предназначен для сжатия и распаковки потоков данных в форматах gzip или deflate (включая deflate-raw). Он доступен в современных браузерах без установки каких-либо пакетов.
Пример того, как сжать данные прямо в браузере:
// Сжатие строки в deflate-raw
async function compress(text) {
const stream = new Blob([text]).stream()
.pipeThrough(new CompressionStream('deflate-raw'));
const buffer = await new Response(stream).arrayBuffer();
// Преобразуем в Base64
return btoa(String.fromCharCode(...new Uint8Array(buffer)));
}
// Распаковка из Base64 deflate-raw
async function decompress(base64) {
return fetch('data:;base64,' + base64)
.then(r => r.body.pipeThrough(
new DecompressionStream('deflate-raw')
))
.then(s => new Response(s).text());
}
Что это говорит нам об ИИ-ассистентах в разработке?
История создания «карты в 500 байтах» примечательна не только технической стороной. Она показывает, как ИИ-инструменты вроде Codex меняют подход к решению задач.
В отличие от традиционных инструментов автодополнения кода, Codex — это совместный партнёр, способный самостоятельно браться за задачи. Система позволяет разработчикам делегировать различные обязанности: написание функций, ответы на вопросы о кодовой базе, исправление ошибок и создание pull request-ов для ревью.
В данном случае Codex помог Иво не просто написать шаблонный код — он помог найти нетривиальное решение: использовать fetch() с Data URI для распаковки, что даже опытные JavaScript-разработчики часто не рассматривают как рабочий паттерн.
Иногда самый ценный вклад ИИ — не сгенерированный код, а подсказка о существовании браузерного API, о котором вы не знали.
Итоги: что взять с собой
Этот маленький проект упаковывает в себя несколько важных уроков для любого разработчика:
- DEFLATE — мощный инструмент для любых текстовых и паттерн-насыщенных данных. Особенно эффективен там, где много повторений.
- Compression Streams API встроен в современные браузеры — вам не нужна библиотека типа
pakoилиzlib.jsдля большинства задач. fetch()работает с Data URI — это открывает возможности для встраивания сжатых ресурсов прямо в JavaScript без отдельных файлов.- ИИ-ассистенты помогают находить неочевидные решения — порой не генерацией кода, а указанием на существующие API и нестандартные паттерны.
- 445 байт — это серьёзно. Полная карта мира, видимая человеческим глазом, в объёме меньше, чем типичный аватар пользователя в мессенджере.
Следующий раз, когда вам нужно будет встроить небольшие статические данные прямо в приложение — вспомните этот трюк. Браузерные API давно стали достаточно мощными, чтобы не тянуть лишние зависимости.