порт демок из курса Такео Игараши на JavaScript

Наткнулся на онлайн-курс Interactive Computer Graphics от Такео Игараши — японского исследователя в области HCI и компьютерной графики. К части демонстраций прилагался исходный код на Java. Захотелось оживить их в браузере.
Демок три:
Ninja Cursors — несколько виртуальных курсоров, управляемых одной мышью. Разные стратегии выбора активного курсора: очередь, одновременная активация, расширяющиеся пузыри-допуски. Идея в том, что на большом экране одного курсора мало.
Autozoom — перетаскивание фрактальной плитки. Чем быстрее тянешь — тем сильнее масштаб «съезжает», чтобы картинка не размывалась в кашу. При отпускании плавно возвращается к нормальному масштабу.
Bubble — жёлтые квадраты, которые при сближении объединяются в «пузыри» с плавной границей. Пузыри можно таскать целиком, двойной клик — разбрасывает квадраты в стороны и возвращает обратно.
Технически
Проект собирается Vite как multi-page app — каждая демка живёт в своём подкаталоге со своим index.html.
Ninja Cursors и Autozoom написаны на TypeScript, Bubble — на чистом JavaScript (оригинал был на Java,
без типов, так и оставил).
Никаких фреймворков — только Canvas 2D и браузерные API.
Ninja Cursors
Самое интересное здесь — Pointer Lock API: мышь захватывается, и дальше работаем с относительным смещением, а не с координатами. Курсоры двигаются в пределах канваса, оборачиваясь через края.
Четыре режима переключаются клавишами 1–4. В режиме Bubble каждый курсор рисует расширяющуюся окружность — цель захватывается, когда круг её касается.
Autozoom
Паттерны — два рисунка (медвежонок и муравей), нарисованных отрезками. Они тайлятся на плоскости на двух масштабных уровнях (×1 и ×0.1), образуя фрактал. Логика ускорения/замедления скролла и анимации возврата масштаба взята один в один из оригинального Java-апплета.
Bubble
Самая интересная часть с точки зрения алгоритмов.
Каждый квадрат — источник радиального поля (метабол). Граница кластера — изолиния поля на уровне 1.0. Строится методом Marching Squares: сетка, 16 вариантов ячеек, трассировка замкнутых полигонов, сглаживание Лапласа.
Объединение квадратов в кластеры — Union-Find с гистерезисом: порог слияния и порог разъединения разные (50 и 80 пикселей), чтобы граница не дёргалась туда-сюда.
Анимация «разброса» — итеративное расталкивание точек до минимального расстояния, потом smooth-step
интерполяция туда и обратно через requestAnimationFrame.