Генератор ASCII-арта в стиле FidoNet / демосцены начала 2000-х. Полностью клиентский: обычные статические файлы, ни сервера, ни зависимостей, ни обязательной сборки.
Общественное достояние — Unlicense. Никаких ограничений: берите, меняйте, продавайте, используйте в коммерческих проектах, указывать авторство не нужно и спрашивать разрешения тоже.
Открыть ASCIIFORGE — живая версия на GitHub Pages.
Одним файлом, без сети: dist/asciiforge.html — правый клик, «Сохранить как», дальше работает офлайн.
Pages включается один раз в Settings → Pages: режим Deploy from a branch, ветка
main, папка/ (root).index.htmlлежит в корне и заводится без всякой сборки.
Три равноценных способа:
- Локально. Открыть
index.htmlдвойным кликом — работает прямо сfile://. Именно поэтому скрипты подключены классическими тегами, а не ES-модулями: модули браузер поfile://блокирует, и приложение потребовало бы локальный сервер. - Хостингом. Выложить каталог как статику — GitHub Pages, любой CDN, ведро S3.
- Одним файлом.
npm run buildкладёт всё приложение вdist/asciiforge.html(~65 КБ) — см. ниже.
Нужна только чтобы собрать single-html. Зависимостей нет, нужен лишь Node:
node build.mjs # или npm run build
Скрипт вшивает css/app.css и все js/*.js внутрь index.html и пишет
dist/asciiforge.html — один самодостаточный файл, который можно отправить
письмом, унести на флешке или открыть без сети. Никакой минификации: код
остаётся читаемым, а каждый вшитый файл помечен комментарием, чтобы отладка в
devtools оставалась осмысленной.
Сборка падает с ошибкой, если в JS встретится литерал </script (он бы закрыл
тег раньше времени и молча обрезал бандл) или если после вшивания в HTML
останется внешняя ссылка.
Исходное дерево уже разворачивается как есть, так что для Pages сборка не
обязательна. dist/ лежит в репозитории, поэтому собранный файл отдаётся со
страницы по прямой ссылке;
после правок в js/ или css/ не забудьте пересобрать и закоммитить его заново,
иначе single-html останется на старой версии.
Конвейер, слева направо:
картинка -> source.js -> convert.js -> render.js -> post.js -> canvas
-
source.js — изображение рисуется ровно в холст
cols*FW x rows*FH, так что каждой символьной ячейке достаётся блокFW x FHотсчётов.FWберётся из реальных метрик шрифта, поэтому пропорции нигде не плывут. Тут же: нерезкое маскирование, тон-маппинг, Собель по сетке ячеек. -
glyphs.js — каждый символ активного набора рендерится текущим шрифтом в текущем кегле и сворачивается в вектор покрытия
FW x FH. Никакой зашитой «лесенки плотности»: смена шрифта автоматически меняет и подбор. -
convert.js — сердце. Для каждой ячейки два пути:
- ровные ячейки (низкая дисперсия) идут по быстрому подбору плотности, с предпочтением повторить предыдущий символ строки. Живой художник заливает ровные области длинными одинаковыми прогонами; поячеечный «лучший матч» здесь даёт только шум — это главная причина, по которой машинный ASCII выглядит машинным;
- структурные ячейки идут через полный матчинг: ошибка плотности плюс
корреляция нормализованных векторов. Вес структуры растёт вместе с силой
контура, поэтому на границах сами собой встают
/ \ | _, а внутри объёмов остаётся спокойная заливка.
Поверх — заливка фона символами
$ § ¶ ¤: один доминирующий глиф на тональную ступень плюс редкие отклонения к соседям. -
render.js — отрисовка в canvas 2D. Соседние ячейки одного цвета выводятся одной строкой: шрифт моноширинный, так что браузер сам расставляет глифы по сетке, и вместо ~15000 вызовов
fillTextполучается несколько сотен. -
post.js — WebGL: bright pass -> blur H -> blur V -> композит с bloom, хроматической аберрацией, скан-линиями, кривизной CRT, виньеткой и зерном.
В наборах намеренно отсутствует диапазон U+2500..U+259F. Блоки и рамки — ровно то, что превращает плотный ASCII в кашу. Плотность здесь набирается типографикой.
Соблазн слить их в одну «тему» есть, но это ловушка: набор символов задаёт фактуру, палитра — настроение. Их 6x8 = 48 комбинаций, и интересных среди них заметно больше, чем 8 слитых пресетов. Пресеты в тулбаре как раз и фиксируют удачные пары, не мешая крутить их по отдельности.
| Группа | Ключевое |
|---|---|
| Источник | яркость, контраст, гамма, резкость, шумоподавление, инверсия |
| Сетка | колонок, кегль (= разрешение вывода), интерлиньяж, шрифт |
| Стиль | набор символов, структура/плотность, контуры, детализация, минимальная плотность, длина прогонов, дизеринг |
| Фоновая заливка | плотность фона, порог тьмы, символ фона, вариативность |
| Палитра | палитра, число цветов (2-4), раскладка, разброс по цветам, дизеринг, слипание пятен, цвет контура, порог контура, свечение |
| Пост-обработка | bloom, хром. аберрация, скан-линии, виньетка, зерно, кривизна, экспозиция |
Цвет контура — отдельная краска вне тонального ряда, светлая или тёмная.
Светлая читается как контровой свет поверх формы, тёмная — как обводка под ней.
Это пятый цвет сверх бюджета 2-4, поэтому статус-строка показывает честное
4+1 цв.. Контуры шириной в одну-две ячейки, поэтому медианный фильтр цвета
съел бы их — они переставляются заново уже после слипания пятен.
Символ фона (bgSeed) — индекс в авторском порядке fill текущего стиля,
то есть 0 это $ для Fido, 1 это §, и так далее; выбранный символ показан в
статус-строке. Один доминирующий символ держится на всё полотно, тон влияет
только на то, в какую сторону уходят редкие отклонения, но никогда на сам
доминирующий символ. Человек, заливая фон, выбирает символ и придерживается его;
вывод символа из тонального шага разбрасывает $ по одним строкам и ¶ по
другим, и это читается как нерешительность. При Вариативность = 0 фон состоит
ровно из одного символа.
Ещё два неочевидных, но самых влиятельных:
- Минимальная плотность (
inkFloor) — приподнимает нижнюю границу «чернил» над пробелом. Именно она делает картинку плотной, а не россыпью точек: тени остаются фактурными, а тон несёт цвет. - Разброс по цветам (
colorSpread) — выравнивание гистограммы. Без него ночной кадр сваливает три четверти сетки в самый тёмный цвет палитры, а остальные три работают декорацией.
- PNG — итоговый холст со всей пост-обработкой.
- TXT — чистый текст.
- ANS — текст с truecolor ANSI-escape. Проверяется в терминале:
cat file.ans.
index.html разметка и порядок подключения
css/app.css интерфейс
js/ конвейер: util, charsets, palettes, glyphs, source,
convert, render, post, params, ui, app
build.mjs сборка single-html (опционально)
example.webp пример вывода
- Пакетная обработка и покадровая конвертация видео.
- Дизеринг с сохранением краёв (сейчас Флойд слегка размывает тонкие контуры).
- Свои палитры и наборы символов из UI, шаринг пресета ссылкой.
- Подгружаемые bitmap-шрифты (topaz / IBM VGA) для аутентичной ANSI-метрики.
- Больше шейдеров: phosphor persistence, glitch/datamosh, RGB-маска.
Unlicense — общественное достояние. Ограничений нет никаких: копируйте, меняйте, публикуйте, компилируйте, продавайте, применяйте в любых целях, включая коммерческие. Атрибуция не требуется, разрешение спрашивать не нужно.
