ASCII Skeleton Loader

Скрипт заменяет обычную скелетную загрузку изображения на анимацию: ASCII contrast 0 → ASCII contrast 100 → исходная картинка. Его можно подключить один раз и автоматически применять ко всем изображениям сайта.

1:1 overlay Batch processing Lazy loading MutationObserver Vanilla JS

Как это работает

Скрипт находит изображения по CSS-селектору. Для каждой картинки он создаёт ASCII-представление, накладывает его точно поверх реальной области изображения и анимирует контраст от 0 до 100. После этого ASCII плавно исчезает, а исходное изображение проявляется.

Последовательность:

ASCII contrast 0 → промежуточные кадры → ASCII contrast 100 → fade → default image.

Быстрое подключение: куда именно вставлять код

Самое важное: сначала идёт блок window.ASCII_SKELETON_CONFIG, а уже после него — подключение ascii-skeleton-site-loader.js. Если поменять их местами, скрипт запустится с настройками по умолчанию.

Вариант 1. Обычный HTML-сайт

Откройте HTML-файл страницы и найдите закрывающий тег </body>. Вставьте оба блока прямо перед ним.

Было:

<body>
  ...контент страницы...
</body>

Должно стать так:

<body>
  ...контент страницы...

  <script>
  window.ASCII_SKELETON_CONFIG = {
    selector: 'img:not([data-ascii-skip])',
    columns: 96,
    frames: 24,
    asciiDuration: 1400,
    fadeDuration: 500,
    charset: '@%#*+=-:. ',
    invert: false,
    textColor: '#111111',
    background: '#ffffff',
    lazy: true,
    rootMargin: '400px',
    observeMutations: true
  };
  </script>

  <script src="/assets/ascii-skeleton-site-loader.js"></script>
</body>
Почему перед </body>?

К этому моменту основной HTML страницы уже разобран браузером, поэтому loader сразу может найти изображения, не блокируя начальную отрисовку страницы.

Куда положить сам JS-файл

Скачайте ascii-skeleton-site-loader.js и положите его в папку со статическими файлами сайта. Например:

project/
├── index.html
├── assets/
│   └── ascii-skeleton-site-loader.js
└── images/
    ├── product-1.webp
    └── product-2.webp

Тогда путь в HTML будет:

<script src="/assets/ascii-skeleton-site-loader.js"></script>

Если файл лежит рядом с HTML-страницей, используйте:

<script src="./ascii-skeleton-site-loader.js"></script>

Вариант 2. Один общий шаблон для всего сайта

Если у сайта есть общий layout, footer, template или master-page, вставьте два блока туда один раз. Тогда loader автоматически будет работать на всех страницах, которые используют этот шаблон.

<!-- общий footer / layout сайта -->

<script>
window.ASCII_SKELETON_CONFIG = {
  selector: 'img:not([data-ascii-skip])',
  columns: 96,
  frames: 24,
  asciiDuration: 1400,
  fadeDuration: 500,
  lazy: true,
  observeMutations: true
};
</script>

<script src="/assets/ascii-skeleton-site-loader.js"></script>

Вариант 3. Подключение прямо с GitHub Pages

Если вы уже выложили проект на GitHub Pages, сам JS-файл можно не копировать в проект сайта. Тогда внизу страницы перед </body> вставляется:

<script>
window.ASCII_SKELETON_CONFIG = {
  selector: 'img:not([data-ascii-skip])',
  columns: 96,
  frames: 24,
  asciiDuration: 1400,
  fadeDuration: 500,
  lazy: true,
  observeMutations: true
};
</script>

<script src="https://sergeybuharev.github.io/ascii-skeleton-loader/ascii-skeleton-site-loader.js"></script>
GitHub Pages удобно использовать для демо и тестирования. Для production-магазина лучше хранить JS на своём домене или CDN.

Как проверить, что всё подключилось

1
Откройте страницу сайта.
2
Перезагрузите страницу с очищенным кэшем: Ctrl+Shift+R / Cmd+Shift+R.
3
У изображений должен появиться переход ASCII contrast 0 → 100 → исходное изображение.
4
Если эффекта нет, откройте DevTools → Console и проверьте, что нет ошибки 404 на ascii-skeleton-site-loader.js.

Применить ко всем изображениям сайта

По умолчанию можно использовать селектор:

selector: 'img:not([data-ascii-skip])'

Тогда скрипт обработает практически все теги <img>, кроме явно исключённых.

Что именно вставлять в код сайта

У подключения есть две части, и у каждой своя задача.

Часть 1 — настройки
<script>
window.ASCII_SKELETON_CONFIG = {
  selector: '.product-card img',
  columns: 96,
  frames: 24,
  asciiDuration: 1400,
  fadeDuration: 500,
  lazy: true,
  observeMutations: true
};
</script>

Этот кусок ничего сам не запускает. Он только задаёт настройки будущему loader-скрипту. Поэтому он должен стоять выше подключения JS-файла.

Часть 2 — сам loader
<script src="/assets/ascii-skeleton-site-loader.js"></script>

Этот файл читает настройки из первой части, находит подходящие изображения и запускает эффект.

Минимальный рабочий пример целиком

<!doctype html>
<html lang="ru">
<head>
  <meta charset="UTF-8">
  <title>Магазин</title>
</head>

<body>

  <div class="product-card">
    <img src="/images/shoes.webp" alt="Shoes">
  </div>

  <div class="product-card">
    <img src="/images/jacket.webp" alt="Jacket">
  </div>

  <script>
  window.ASCII_SKELETON_CONFIG = {
    selector: '.product-card img',
    columns: 96,
    frames: 24,
    asciiDuration: 1400,
    fadeDuration: 500,
    lazy: true,
    observeMutations: true
  };
  </script>

  <script src="/assets/ascii-skeleton-site-loader.js"></script>
</body>
</html>

Если у вас уже есть другие script-теги

Ничего удалять не нужно. Просто добавьте ASCII Loader рядом с ними. Главное — чтобы его конфиг шёл раньше самого loader-файла.

<script src="/assets/app.js"></script>

<script>
window.ASCII_SKELETON_CONFIG = {
  selector: '.product-card img'
};
</script>
<script src="/assets/ascii-skeleton-site-loader.js"></script>

<script src="/assets/analytics.js"></script>

Если loader должен работать только на одной странице

Вставьте эти два блока только в HTML этой страницы. В остальные страницы сайта ничего добавлять не нужно.

Если loader должен работать на всём сайте

Добавьте эти два блока в общий шаблон, который присутствует на каждой странице: например, footer, layout, base.html, общий template CMS или основной layout приложения.

Пример для интернет-магазина

Лучше обрабатывать не вообще все изображения, а только фотографии товаров. Например, если карточки имеют класс product-card:

window.ASCII_SKELETON_CONFIG = {
  selector: '.product-card img',
  columns: 84,
  frames: 20,
  asciiDuration: 1000,
  fadeDuration: 350,
  charset: '@%#*+=-:. ',
  textColor: '#111111',
  background: '#ffffff',
  lazy: true,
  rootMargin: '500px',
  observeMutations: true
};

С lazy: true картинки начинают обрабатываться незадолго до того, как пользователь доскроллит до них. Это полезнее для больших каталогов.

Как исключить отдельное изображение

Добавьте атрибут data-ascii-skip:

<img
  src="/logo.svg"
  alt="Logo"
  data-ascii-skip
>

При стандартном селекторе логотип будет пропущен.

Настройки

Параметр Что делает Пример
selector CSS-селектор изображений, которые нужно обрабатывать. '.product-card img'
columns Количество ASCII-колонок. Больше = выше детализация и нагрузка. 96
frames Число дискретных кадров между contrast 0 и contrast 100. 24
asciiDuration Длительность ASCII-фазы в миллисекундах. 1400
fadeDuration Длительность перехода из ASCII в исходную картинку. 500
charset Набор символов от плотных к светлым. '@%#*+=-:. '
invert Инвертирует соответствие яркости символам. false
textColor Цвет ASCII. '#111111'
background Фон ASCII-слоя. '#ffffff'
lazy Использовать IntersectionObserver и не обрабатывать весь каталог сразу. true
rootMargin Насколько заранее начать обработку перед viewport. '400px'
observeMutations Следить за новыми изображениями, появляющимися после первого рендера страницы. true

Динамические изображения

Если каталог догружается через infinite scroll, AJAX, React/Vue-компоненты или фильтры, оставьте:

observeMutations: true

Скрипт следит за DOM через MutationObserver и автоматически добавляет новые изображения в очередь.

Ручной повторный scan

Также можно вызвать:

window.AsciiSkeleton.scan();

Или обработать конкретный тег изображения:

const image = document.querySelector('#hero-image');
window.AsciiSkeleton.process(image);

CORS и изображения с другого домена

Для превращения картинки в ASCII браузеру необходимо прочитать её пиксели через canvas. У изображений с другого домена это может быть запрещено политикой CORS.

Самый надёжный вариант — хранить картинки и скрипт на своём домене/CDN с корректными CORS-заголовками.

Если изображение нельзя прочитать, скрипт оставляет оригинальную картинку без ASCII-эффекта, а не ломает страницу.

Production для большого магазина

Текущая универсальная версия строит ASCII после получения пикселей изображения браузером. Для обычного сайта этого достаточно.

Но если нужно, чтобы ASCII-скелет конкретной фотографии был доступен ещё до загрузки оригинального файла, нужен build-time этап:

1
На сервере или во время сборки пройти по всем изображениям каталога.
2
Для каждого изображения заранее посчитать маленькую luma/ASCII-карту.
3
Сохранить эти данные в manifest рядом с URL изображения.
4
Клиентский loader сначала показывает manifest-ASCII, а картинку загружает параллельно.

Для сотен или тысяч товарных фотографий это наиболее правильная архитектура: эффект появляется мгновенно и не требует декодировать каждое изображение заранее на клиенте.

Подключение через GitHub Pages

Если репозиторий называется ascii-skeleton-loader в аккаунте sergeybuharev, после включения GitHub Pages файл будет доступен примерно по адресу:

https://sergeybuharev.github.io/ascii-skeleton-loader/ascii-skeleton-site-loader.js

Тогда подключение выглядит так:

<script>
window.ASCII_SKELETON_CONFIG = {
  selector: 'img:not([data-ascii-skip])',
  columns: 96,
  frames: 24,
  asciiDuration: 1400,
  fadeDuration: 500,
  lazy: true,
  observeMutations: true
};
</script>

<script src="https://sergeybuharev.github.io/ascii-skeleton-loader/ascii-skeleton-site-loader.js"></script>
Для production-магазина лучше хранить JS на собственном домене или CDN, а GitHub Pages использовать для демо и документации.