npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

aetherbox

v0.1.0

Published

Lightweight ES Module lightbox — images, video, HTML, zoom/pan, carousel, i18n

Readme

Aetherbox

A lightweight, zero-dependency-at-runtime ES Module lightbox for images, video, iframes, and arbitrary HTML — with pinch/zoom, swipe carousel, thumbnails, and i18n out of the box.

Русская версия ниже ↓

Features

  • 🖼️ Images, video, iframes, and raw HTML in one gallery
  • 🎬 Built-in providers for YouTube, Vimeo, VK Video, and Rutube — just drop in a link
  • 🔍 Pinch-to-zoom and pan on images (mouse wheel, double-click, touch gestures)
  • 👉 Swipe navigation between slides on touch devices
  • 🖱️ Drag-to-dismiss style preview swipe
  • 🧵 Thumbnail strip with click-to-jump
  • 🌍 i18n-ready — English built in, Russian available as an optional import, easy to add your own
  • 📦 Tree-shakeable ESM — no bundled CSS-in-JS, no jQuery, no runtime dependencies beyond a small peer dependency for gestures
  • Accessible — proper dialog role, aria-modal, keyboard navigation (←/→/Esc/+/-/0)

Demo

<a href="/photos/01-full.jpg" data-thumb="/photos/01-thumb.jpg" data-aetherbox data-aetherbox-group="gallery">
  <img src="/photos/01-thumb.jpg" alt="">
</a>
<a href="/photos/02-full.jpg" data-thumb="/photos/02-thumb.jpg" data-aetherbox data-aetherbox-group="gallery">
  <img src="/photos/02-thumb.jpg" alt="">
</a>
import { Aetherbox } from 'aetherbox';
import 'aetherbox/css';

new Aetherbox().autoInit();

That's it — clicking any linked thumbnail opens the gallery.

Installation

npm install aetherbox @use-gesture/vanilla

@use-gesture/vanilla is a peer dependency used for pinch/zoom/swipe gestures. It is not bundled, so you install it once and Aetherbox uses your copy.

Usage

Auto-binding from markup (declarative)

Mark any link or element with data-aetherbox. Group related items with a shared data-aetherbox-group so they form a single gallery/carousel.

<a href="/img/cat.jpg" data-aetherbox data-aetherbox-group="pets" data-title="My cat"></a>
<a href="https://youtu.be/dQw4w9WgXcQ" data-aetherbox data-aetherbox-group="pets" data-title="A video"></a>

Supported data-* attributes per element:

| Attribute | Description | |------------------------|------------------------------------------------------------| | href / data-src | Source URL (image, video file, embeddable link, or iframe) | | data-type | Force a type: image, video, iframe, html. Auto-detected if omitted (including YouTube/Vimeo/VK/Rutube links). | | data-title | Caption title | | data-description | Caption description | | data-thumb | Thumbnail image shown in the strip (falls back to src for <img>) | | data-html | Raw HTML content, used when data-type="html" | | data-aetherbox-group | Groups elements into one gallery (omit for a single standalone item) |

import { Aetherbox } from 'aetherbox';
import 'aetherbox/css';

const lightbox = new Aetherbox({
  selector: '[data-aetherbox]', // default
});
lightbox.autoInit();

Programmatic API

import { Aetherbox } from 'aetherbox';
import 'aetherbox/css';

const lightbox = new Aetherbox({
  loop: true,
  keyboard: true,
  thumbnails: true,
  counter: true,
  closeOnBackdrop: true,
  zoom: true,
  zoomMin: 1,
  zoomMax: 5,
  zoomStep: 0.6,
  zoomButtons: true,
});

lightbox.add([
  { src: '/img/1.jpg', title: 'First image' },
  { src: 'https://youtu.be/dQw4w9WgXcQ', title: 'A video' },
  { type: 'html', html: '<p>Custom content</p>' },
]);

lightbox.open(0);

Methods

| Method | Description | |------------------------------|----------------------------------------------------------------| | add(item \| item[]) | Append one or more items | | remove(index) | Remove an item by index | | clear() | Remove all items | | open(index = 0) | Open the lightbox at a given slide | | close() | Close the lightbox | | goto(index) | Jump to a specific slide while open | | next() / prev() | Navigate slides | | loadFrom(url, fetchOpts?) | Fetch a JSON array of items and add() them | | autoInit(root = document) | Scan the DOM for [data-aetherbox] elements and bind them | | destroy() | Tear down the instance and remove listeners |

Events

Aetherbox extends a small EventEmitter. Subscribe with .on(event, handler):

lightbox.on('open', ({ index }) => {});
lightbox.on('change', ({ index, prev, item }) => {});
lightbox.on('shown', ({ index, item }) => {});
lightbox.on('error', ({ index, item, error }) => {});
lightbox.on('close', () => {});
lightbox.on('destroy', () => {});
lightbox.on('loadstart', ({ url }) => {});
lightbox.on('loadend', ({ url, count }) => {});
lightbox.on('loaderror', ({ url, error }) => {});

Item shape

{
  src: string;          // URL — image, video file, embeddable link, or iframe src
  type?: 'image' | 'video' | 'iframe' | 'html'; // auto-detected if omitted
  title?: string;
  description?: string;
  thumb?: string;        // thumbnail URL for the thumbnail strip
  html?: string;          // used when type === 'html'
  width?: string | number;  // for video/iframe frame sizing
  height?: string | number;
}

Video providers

Links matching these patterns are auto-detected and embedded — no extra config:

  • YouTube (youtube.com, youtu.be)
  • Vimeo (vimeo.com)
  • VK Video (vkvideo.ru, vk.com/video, vk.com/clip)
  • Rutube (rutube.ru)

Internationalization

English is built in. To use another language:

import { Aetherbox } from 'aetherbox';
import { ru } from 'aetherbox/locale/ru';
import 'aetherbox/css';

const lightbox = new Aetherbox({ locale: ru });

You can also override individual strings:

new Aetherbox({ locale: { ...ru, close: 'Х' } });

Want to add a new language? Copy src/locale/en.js, translate the values, and either bundle it in your fork or pass it in directly via locale.

Keyboard shortcuts

| Key | Action | |-----------|------------------| | / | Previous / next | | Esc | Close | | + / - | Zoom in / out | | 0 | Reset zoom |

Styling

Import the default styles:

import 'aetherbox/css';

The visual design ("aether" theme) is plain CSS with custom properties, so you can override colors, spacing, and timing by targeting .ab-* classes or redefining CSS variables in your own stylesheet loaded after aetherbox/css.

Browser support

Modern evergreen browsers (ES2020+). No IE11 support.

License

MIT © legkomedia


Aetherbox (на русском)

Лёгкий ES-модульный лайтбокс без зависимостей в рантайме — для изображений, видео, iframe и произвольного HTML, со встроенным zoom/pan, свайп-каруселью, миниатюрами и поддержкой нескольких языков.

Возможности

  • 🖼️ Изображения, видео, iframe и HTML в одной галерее
  • 🎬 Готовые провайдеры видео: YouTube, Vimeo, VK Видео, Rutube — достаточно вставить ссылку
  • 🔍 Zoom и pan на изображениях (колесо мыши, двойной клик, тач-жесты)
  • 👉 Свайп-навигация между слайдами на тач-устройствах
  • 🖱️ Drag-preview при смене слайдов
  • 🧵 Полоса миниатюр с переходом по клику
  • 🌍 Готов к i18n — английский встроен, русский доступен опционально, легко добавить свой язык
  • 📦 Tree-shakeable ESM — без CSS-in-JS, без jQuery, без рантайм-зависимостей (кроме небольшого peer-пакета для жестов)
  • Доступность — корректная роль dialog, aria-modal, навигация с клавиатуры (←/→/Esc/+/-/0)

Демо

<a href="/photos/01-full.jpg" data-thumb="/photos/01-thumb.jpg" data-aetherbox data-aetherbox-group="gallery">
  <img src="/photos/01-thumb.jpg" alt="">
</a>
<a href="/photos/02-full.jpg" data-thumb="/photos/02-thumb.jpg" data-aetherbox data-aetherbox-group="gallery">
  <img src="/photos/02-thumb.jpg" alt="">
</a>
import { Aetherbox } from 'aetherbox';
import 'aetherbox/css';

new Aetherbox().autoInit();

Готово — клик по любой миниатюре открывает галерею.

Установка

npm install aetherbox @use-gesture/vanilla

@use-gesture/vanilla — peer-зависимость, используемая для жестов zoom/pan/swipe. Она не встраивается в сборку, поэтому устанавливается один раз отдельно.

Использование

Автоматическая привязка из разметки (декларативно)

Помечайте ссылки или элементы атрибутом data-aetherbox. Объединяйте связанные элементы общим data-aetherbox-group, чтобы они образовали одну галерею/карусель.

<a href="/img/cat.jpg" data-aetherbox data-aetherbox-group="pets" data-title="Мой кот"></a>
<a href="https://youtu.be/dQw4w9WgXcQ" data-aetherbox data-aetherbox-group="pets" data-title="Видео"></a>

Поддерживаемые data-* атрибуты:

| Атрибут | Описание | |-------------------------|------------------------------------------------------------------| | href / data-src | URL источника (картинка, видеофайл, ссылка для embed или iframe) | | data-type | Принудительный тип: image, video, iframe, html. Если не указан — определяется автоматически (включая ссылки YouTube/Vimeo/VK/Rutube). | | data-title | Заголовок подписи | | data-description | Текст описания | | data-thumb | Миниатюра для полосы превью (для <img> берётся src, если не указано) | | data-html | Произвольный HTML, используется при data-type="html" | | data-aetherbox-group | Группирует элементы в одну галерею (если не указан — отдельный элемент) |

import { Aetherbox } from 'aetherbox';
import 'aetherbox/css';

const lightbox = new Aetherbox({
  selector: '[data-aetherbox]', // по умолчанию
});
lightbox.autoInit();

Программный API

import { Aetherbox } from 'aetherbox';
import 'aetherbox/css';

const lightbox = new Aetherbox({
  loop: true,
  keyboard: true,
  thumbnails: true,
  counter: true,
  closeOnBackdrop: true,
  zoom: true,
  zoomMin: 1,
  zoomMax: 5,
  zoomStep: 0.6,
  zoomButtons: true,
});

lightbox.add([
  { src: '/img/1.jpg', title: 'Первая картинка' },
  { src: 'https://youtu.be/dQw4w9WgXcQ', title: 'Видео' },
  { type: 'html', html: '<p>Произвольный контент</p>' },
]);

lightbox.open(0);

Методы

| Метод | Описание | |--------------------------------|--------------------------------------------------------------------| | add(item \| item[]) | Добавить один или несколько элементов | | remove(index) | Удалить элемент по индексу | | clear() | Удалить все элементы | | open(index = 0) | Открыть лайтбокс на нужном слайде | | close() | Закрыть лайтбокс | | goto(index) | Перейти на слайд, пока лайтбокс открыт | | next() / prev() | Навигация по слайдам | | loadFrom(url, fetchOpts?) | Загрузить JSON-массив элементов и добавить через add() | | autoInit(root = document) | Найти [data-aetherbox] элементы в DOM и привязать их | | destroy() | Уничтожить инстанс и снять слушатели |

События

Aetherbox наследует небольшой EventEmitter. Подписка через .on(event, handler):

lightbox.on('open', ({ index }) => {});
lightbox.on('change', ({ index, prev, item }) => {});
lightbox.on('shown', ({ index, item }) => {});
lightbox.on('error', ({ index, item, error }) => {});
lightbox.on('close', () => {});
lightbox.on('destroy', () => {});
lightbox.on('loadstart', ({ url }) => {});
lightbox.on('loadend', ({ url, count }) => {});
lightbox.on('loaderror', ({ url, error }) => {});

Структура элемента

{
  src: string;          // URL — картинка, видеофайл, embed-ссылка или iframe src
  type?: 'image' | 'video' | 'iframe' | 'html'; // если не указан — определяется автоматически
  title?: string;
  description?: string;
  thumb?: string;        // URL миниатюры для полосы превью
  html?: string;          // используется при type === 'html'
  width?: string | number;  // размер рамки для video/iframe
  height?: string | number;
}

Видео-провайдеры

Ссылки следующих видов определяются автоматически и встраиваются без доп. настройки:

  • YouTube (youtube.com, youtu.be)
  • Vimeo (vimeo.com)
  • VK Видео (vkvideo.ru, vk.com/video, vk.com/clip)
  • Rutube (rutube.ru)

Локализация

Английский встроен по умолчанию. Чтобы использовать другой язык:

import { Aetherbox } from 'aetherbox';
import { ru } from 'aetherbox/locale/ru';
import 'aetherbox/css';

const lightbox = new Aetherbox({ locale: ru });

Можно переопределить отдельные строки:

new Aetherbox({ locale: { ...ru, close: 'Х' } });

Хотите добавить новый язык? Скопируйте src/locale/en.js, переведите значения и либо подключите файл в своём форке, либо передайте объект напрямую через locale.

Горячие клавиши

| Клавиша | Действие | |-----------|-------------------| | / | Назад / вперёд | | Esc | Закрыть | | + / - | Увеличить / уменьшить | | 0 | Сбросить зум |

Стили

Подключите стандартные стили:

import 'aetherbox/css';

Визуальное оформление (тема "aether") — это обычный CSS с переменными, поэтому можно переопределить цвета, отступы и тайминги, переписав классы .ab-* или CSS-переменные в своём стиле, подключённом после aetherbox/css.

Поддержка браузеров

Современные браузеры (ES2020+). Без поддержки IE11.

Лицензия

MIT © legkomedia