needhelp
← Back to blog

@xingwangzhe/tags-cloud: Мультимодальный движок 3D-облака тегов на чистой математике

by needhelp
TagsCloud
3D
TypeScript
Math
Visualization
Open Source

@xingwangzhe/tags-cloud: Мультимодальный движок 3D-облака тегов на чистой математике

GitHub: xingwangzhe/tags-cloud · Демо: tagscloud.needhelp.icu · npm: @xingwangzhe/tags-cloud · Лицензия: MIT · Версия: v0.9.0


1. Введение: Переосмысление 3D-облака тегов для современного веба

Облако тегов остаётся одним из основных элементов веб-визуализации уже более двух десятилетий, эволюционировав от простых взвешенных списков слов к иммерсивным трёхмерным интерактивным пространственным скульптурам. Среди наиболее значимых вкладов в эту эволюцию — cong-min/TagCloud, лёгкая JavaScript-библиотека, показавшая, что сферу из вращающихся текстовых меток можно реализовать с минимальными затратами и без внешних зависимостей. Имея 390 звёзд и 93 форка на GitHub, оригинальный TagCloud заложил паттерн, который бесчисленные разработчики адаптировали для портфолио, демонстрации навыков и панелей визуализации данных. Его ключевое новшество заключалось в доказательстве того, что 3D-облака тегов не обязаны полагаться на тяжёлые WebGL-фреймворки или внешние движки рендеринга; вместо этого прямые тригонометрические расчёты в сочетании с аккуратным DOM-позиционированием могут давать удивительно впечатляющие визуальные результаты.

Встречайте @xingwangzhe/tags-cloud — выполненную с нуля переработку концепции 3D-облака тегов, сохраняющую математическую элегантность предшественника, но радикально расширяющую его возможности, модернизирующую архитектуру и раздвигающую границы того, что может рендерить облако тегов. Это не просто форк или добавление функциональности; это фундаментальный архитектурный сдвиг от текстового, тяжеловесного DOM-рендерера к мультимодальному движку, способному отображать текст, изображения, SVG-графику, произвольный HTML, видео и даже полноценные веб-компоненты — все они вращаются вместе в математически точном трёхмерном пространстве. Библиотека достигает этой универсальности, сохраняя исключительно компактный размер — примерно 3KB в gzip, — не имея ни одной runtime-зависимости и будучи построенной на современном инструментарии: Bun в качестве JavaScript-среды, Vite в качестве сборщика и TypeScript для полной типобезопасности во всей кодовой базе.

Слоган проекта — «мультимодальное 3D-облако тегов · движок на чистой математике» — отражает его двойственную природу. С одной стороны, это практичная библиотека UI-компонентов, которую разработчики могут встраивать в любой веб-проект для создания визуально впечатляющих сфер из тегов. С другой стороны, это математический движок, разлагающий сложную задачу рендеринга 3D-облака тегов на три чистых, детерминированных и красиво разделимых геометрических операции: распределение по сфере Фибоначчи для начального позиционирования, умножение матриц поворота для пространственных трансформаций и перспективная проекция для depth-осознанного 2D-рендеринга. Каждая из этих операций реализована в собственном модуле внутри директории src/core/, что делает кодовую базу не только хорошо поддерживаемой, но и отличным образовательным ресурсом для всех, кто хочет понять математику 3D-компьютерной графики без усложняющей сложности полного конвейера рендеринга.

Следующие разделы представляют всестороннее техническое погружение в каждый аспект @xingwangzhe/tags-cloud: от алгоритма распределения по сфере на основе золотого сечения до вдохновлённой кватернионами arcball-модели взаимодействия, от двойной архитектуры Canvas/DOM до адаптивного дизайна, обеспечивающего бесшовную работу на десктопах и мобильных устройствах. Будь вы разработчиком, оценивающим эту библиотеку для своего следующего проекта, графическим программистом, интересующимся лёгкими 3D-техниками, или математиком, любопытствующим о реальных применениях решётки Фибоначчи, — эта статья предлагает подробные объяснения, математические выводы, архитектурные схемы и аннотированные примеры кода, освещающие каждую грань этого замечательного программного продукта.


2. Математический фундамент: Три столпа 3D-рендеринга

В основе @xingwangzhe/tags-cloud лежит трио математических операций, которые в композиции превращают абстрактный список элементов контента в визуально связную вращающуюся сферу. Эти операции — распределение, поворот и проекция — реализованы в трёх модулях внутри src/core/, каждый отвечает за одно геометрическое преобразование. Такое разделение ответственности — не просто архитектурное предпочтение; оно отражает фундаментальную структуру конвейеров 3D-компьютерной графики, где генерация вершин, трансформация модели и камерная проекция являются отдельными стадиями, которые можно независимо оптимизировать, тестировать и понимать.

flowchart LR
    subgraph Input["📥 Входной слой"]
        TAGS["TagItem[]
(text | image | SVG | HTML | video | element)"] OPTS["TagCloudOptions
(radius, spin, colors, callbacks)"] end subgraph CoreEngine["⚙️ Чистый математический движок (src/core/)"] direction TB DIST["🔵 distribution.ts
Сфера Фибоначчи
N точек → 3D координаты"] ROT["🟢 rotation.ts
Матрицы поворота
3D точки → повёрнутые 3D точки"] PROJ["🔴 projection.ts
Перспективная проекция
повёрнутые 3D → 2D + глубина"] end subgraph RenderLayer["🎨 Слой рендеринга"] direction TB CANVAS["Canvas 2D API
(текст + изображения)"] DOM["DOM-оверлей
(SVG + HTML + видео + элементы)"] end subgraph Interaction["👤 Слой взаимодействия"] MOUSE["Мышь / Сенсорное перетаскивание"] INERTIA["Затухание инерции
(0.96/кадр)"] end TAGS --> DIST OPTS --> DIST DIST -->|"Vec3[]"| ROT ROT -->|"Повёрнутые Vec3[]"| PROJ PROJ -->|"ProjectedTag[]
(x, y, z, scale, alpha)"| CANVAS PROJ --> DOM MOUSE --> INERTIA INERTIA -->|"углы поворота"| ROT style CoreEngine fill:#1a1a2e,stroke:#16213e style Input fill:#0f3460,stroke:#16213e style RenderLayer fill:#533483,stroke:#16213e style Interaction fill:#e94560,stroke:#16213e,color:#fff

2.1 Распределение Фибоначчи по сфере: Золотая геометрия размещения точек

Первый и, пожалуй, наиболее эстетически критичный шаг в создании 3D-облака тегов — определение позиции каждой метки на сфере. Наивный подход — размещать метки через равные интервалы по широте и долготе — неизбежно приводит к кластеризации у полюсов, где сходятся линии меридианов, и разреженным областям у экватора. Алгоритм сферы Фибоначчи элегантно решает эту проблему, создавая распределение точек, которое remarkably равномерно по всей поверхности сферы, без видимой кластеризации или пробелов независимо от количества точек.

Своё название алгоритм получил от золотого сечения (\varphi = \frac{1 + \sqrt{5}}{2} \approx 1.6180339887) — математической константы, повсеместно встречающейся в природе: от расположения семян подсолнуха до спиралей раковины наутилуса. Связь с числами Фибоначчи — последовательностью, где каждый член равен сумме двух предыдущих, — в том, что отношение последовательных чисел Фибоначчи сходится к золотому сечению по мере продвижения по ряду. В контексте распределения по сфере иррациональность золотого сечения гарантирует, что последовательные точки всегда размещаются под неповторяющимися углами, создавая апериодический спиральный паттерн, равномерно заполняющий поверхность сферы.

Конкретная реализация в src/core/distribution.ts использует вариацию решётки Фибоначчи, оптимизированную для сферического отображения. Для сферы радиуса (R) с (N) точками, которые нужно распределить, алгоритм вычисляет сферические координаты, а затем преобразует их в декартовы координаты ((x, y, z)) для каждой точки (i \in {0, 1, 2, \ldots, N-1}). Угол широты (\phi) (отсчитываемый от положительной оси z, то есть от Северного полюса) вычисляется через арккосинус для обеспечения равномерного распределения вдоль оси z:

ϕi=arccos(1+2i+1N)\phi_i = \arccos\left(-1 + \frac{‘{’}2i + 1{‘}’}{‘{’}N{‘}’}\right)

Эта формула помещает первую точку чуть ниже Северного полюса, а последнюю — чуть выше Южного, причём сдвиг (+0.5) (заложенный в числителе (2i + 1)) гарантирует, что ни одна точка не окажется точно на полюсе. Это тонкое adjustment критически важно, поскольку предотвращает визуальный артефакт, когда метка находится прямо на верхушке или дне сферы, где вращение было бы почти незаметно. Функция (\arccos) преобразует равномерно распределённый линейный параметр в косинусно-взвешенное угловое распределение, компенсируя тот факт, что у сферы меньше площади поверхности у полюсов и больше — у экватора.

Угол долготы (\theta) (измеряемый в плоскости xy от положительной оси x) вычисляется масштабированием (\phi) на (\sqrt{N\pi}), что создаёт характерный спиральный паттерн:

θi=Nπϕi\theta_i = \sqrt{‘{’}N\pi{‘}’} \cdot \phi_i

Коэффициент (\sqrt{N\pi}) выводится из соотношения между золотым углом и общей площадью поверхности сферы. С ростом (N) это масштабирование гарантирует, что спираль оборачивается вокруг сферы нужное количество раз для сохранения равномерных промежутков между соседними точками. В результате каждый следующий поворот точки относительно предыдущего составляет примерно золотой угол (\approx 137.5°) при наблюдении вдоль оси z, что повторяет филлотактические спирали, встречающиеся в природе.

Наконец, эти сферические координаты преобразуются в декартовы по стандартным формулам:

xi=Rcos(θi)sin(ϕi)x_i = R \cdot \cos(\theta_i) \cdot \sin(\phi_i)

yi=Rsin(θi)sin(ϕi)y_i = R \cdot \sin(\theta_i) \cdot \sin(\phi_i)

zi=Rcos(ϕi)z_i = R \cdot \cos(\phi_i)

Полученные точки удовлетворяют уравнению сферы (x_i^2 + y_i^2 + z_i^2 = R^2) и распределены с равномерностью, которая превосходит гораздо более вычислительно затратные методы на основе оптимизации. Следующая выносная формула суммирует полный алгоритм сферы Фибоначчи:

FibonacciSphere(N,R):i[0,N1]:{‘{’}ϕi=arccos(1+2i+1N)θi=NπϕiPi=(Rsinϕicosθi,  Rsinϕisinθi,  Rcosϕi)\boxed{‘{’}\text{‘{’}FibonacciSphere{‘}’}(N, R): \quad \forall i \in [0, N-1]: \begin{‘{’}cases{‘}’} \phi_i = \arccos\left(-1 + \frac{‘{’}2i+1{‘}’}{‘{’}N{‘}’}\right) \ \theta_i = \sqrt{‘{’}N\pi{‘}’} \cdot \phi_i \ P_i = (R\sin\phi_i\cos\theta_i, ; R\sin\phi_i\sin\theta_i, ; R\cos\phi_i) \end{‘{’}cases{‘}’}{‘}’}

Реализация на TypeScript в src/core/distribution.ts remarkably лаконична, отражая элегантную простоту алгоритма:

export interface Vec3 { x: number; y: number; z: number; }
export function fibonacciSphere(n: number, R: number): Vec3[] {
const points: Vec3[] = [];
for (let i = 0; i < n; i++) {
const phi = Math.acos(-1 + (2 * i + 1) / n);
const theta = Math.sqrt(n * Math.PI) * phi;
points.push({
x: R * Math.cos(theta) * Math.sin(phi),
y: R * Math.sin(theta) * Math.sin(phi),
z: R * Math.cos(phi),
});
}
return points;
}

Эта функция возвращает массив объектов Vec3, которые служат начальными позициями для всех меток в облаке. Алгоритм работает за время (\mathcal{O}(N)), что делает его пригодным для облаков с сотнями элементов. На практике большинство облаков тегов содержат от 20 до 100 меток, для которых этот расчёт практически мгновенен.

2.2 3D-поворот: Умножение матриц в пространственной области

После того как метки размещены на поверхности сферы, следующий шаг — обеспечить вращение: как непрерывное автоматическое, так и управляемое пользователем через перетаскивание. Библиотека реализует вращение с помощью композитных матриц поворота, выровненных по осям, а именно — последовательных поворотов вокруг оси Y, а затем вокруг оси X. Этот подход вычислительно эффективен, прост для понимания и полностью достаточен для случая облака тегов, где вращения всегда выполняются относительно сферы с центром в начале координат.

Математическая основа этих вращений — линейная алгебра. Матрица поворота в 3D — это ортогональная матрица (3 \times 3) с определителем 1, которая преобразует координаты точки, сохраняя её расстояние от начала координат. Для поворота на угол (\alpha) вокруг оси Y матрица поворота (R_y(\alpha)) имеет вид:

Ry(α)=(cosα0sinα010sinα0cosα)R_y(\alpha) = \begin{‘{’}pmatrix{‘}’} \cos\alpha & 0 & \sin\alpha \ 0 & 1 & 0 \ -\sin\alpha & 0 & \cos\alpha \end{‘{’}pmatrix{‘}’}

Для поворота на угол (\beta) вокруг оси X матрица поворота (R_x(\beta)) имеет вид:

Rx(β)=(1000cosβsinβ0sinβcosβ)R_x(\beta) = \begin{‘{’}pmatrix{‘}’} 1 & 0 & 0 \ 0 & \cos\beta & -\sin\beta \ 0 & \sin\beta & \cos\beta \end{‘{’}pmatrix{‘}’}

Библиотека применяет эти повороты последовательно: сначала вокруг оси Y, затем вокруг оси X. Для точки (P = (x, y, z)) поворот вокруг оси Y даёт промежуточную точку (P’):

(xyz)=Ry(α)(xyz)=(xcosα+zsinαyxsinα+zcosα)\begin{‘{’}pmatrix{‘}’} x' \ y' \ z' \end{‘{’}pmatrix{‘}’} = R_y(\alpha) \begin{‘{’}pmatrix{‘}’} x \ y \ z \end{‘{’}pmatrix{‘}’} = \begin{‘{’}pmatrix{‘}’} x\cos\alpha + z\sin\alpha \ y \ -x\sin\alpha + z\cos\alpha \end{‘{’}pmatrix{‘}’}

Затем к (P’) применяется поворот вокруг оси X, дающий итоговую повёрнутую точку (P’’):

(xyz)=Rx(β)(xyz)=(xycosβzsinβysinβ+zcosβ)\begin{‘{’}pmatrix{‘}’} x'' \ y'' \ z'' \end{‘{’}pmatrix{‘}’} = R_x(\beta) \begin{‘{’}pmatrix{‘}’} x' \ y' \ z' \end{‘{’}pmatrix{‘}’} = \begin{‘{’}pmatrix{‘}’} x' \ y'\cos\beta - z'\sin\beta \ y'\sin\beta + z'\cos\beta \end{‘{’}pmatrix{‘}’}

Реализация в src/core/rotation.ts разворачивает эти матричные умножения в прямые арифметические операции, избегая накладных расходов на выделение объектов матриц и умножение. Для одной точки функция поворота вычисляет:

y1=ycosα+z(sinα)z1=ysinα+zcosαx2=xcosβ+z1sinβz2=z1cosβxsinβP=(x2,  y1,  z2)\boxed{‘{’}\begin{‘{’}aligned{‘}’} y_1 &= y \cdot \cos\alpha + z \cdot (-\sin\alpha) \ z_1 &= y \cdot \sin\alpha + z \cdot \cos\alpha \ x_2 &= x \cdot \cos\beta + z_1 \cdot \sin\beta \ z_2 &= z_1 \cdot \cos\beta - x \cdot \sin\beta \ P'' &= (x_2, ; y_1, ; z_2) \end{‘{’}aligned{‘}’}{‘}’}

Функция rotatePoints выполняет это преобразование пакетно для всех меток:

export function rotatePoints(points: Vec3[], a: number, b: number): Vec3[] {
const sinA = Math.sin(a), cosA = Math.cos(a);
const sinB = Math.sin(b), cosB = Math.cos(b);
return points.map((p) => {
const y1 = p.y * cosA + p.z * -sinA;
const z1 = p.y * sinA + p.z * cosA;
const x2 = p.x * cosB + z1 * sinB;
return { x: x2, y: y1, z: z1 * cosB - p.x * sinB };
});
}

2.3 Перспективная проекция: Из 3D-пространства на 2D-экран

Финальная математическая операция преобразует повёрнутые 3D-координаты в 2D-позиции на экране. Библиотека использует упрощённую, но весьма эффективную модель проекции, которая вычисляет коэффициент масштаба и коэффициент непрозрачности на основе глубины, с параметром перспективной глубины, равным удвоенному радиусу сферы:

per=2depth2depth+z=4R4R+z\text{‘{’}per{‘}’} = \frac{‘{’}2 \cdot \text{‘{’}depth{‘}’}{‘}’}{‘{’}2 \cdot \text{‘{’}depth{‘}’} + z{‘}’} = \frac{‘{’}4R{‘}’}{‘{’}4R + z{‘}’}

Коэффициент непрозрачности (alpha) использует квадратичную зависимость с корректировкой смещения:

alpha=clamp(per20.25,  0,  1)\text{‘{’}alpha{‘}’} = \text{‘{’}clamp{‘}’}\left(\text{‘{’}per{‘}’}^2 - 0.25, ; 0, ; 1\right)

Полный конвейер проекции суммируется как:

peri=2depth2depth+ziscalei=perialphai=min(1,  max(0,  peri20.25))Pi2D=(xiscalei,  yiscalei,  scalei,  alphai)\boxed{‘{’}\begin{‘{’}aligned{‘}’} \text{‘{’}per{‘}’}_i &= \frac{‘{’}2 \cdot \text{‘{’}depth{‘}’}{‘}’}{‘{’}2 \cdot \text{‘{’}depth{‘}’} + z_i{‘}’} \ \text{‘{’}scale{‘}’}_i &= \text{‘{’}per{‘}’}_i \ \text{‘{’}alpha{‘}’}_i &= \min\left(1, ; \max\left(0, ; \text{‘{’}per{‘}’}_i^2 - 0.25\right)\right) \ P_i^{‘{’}\text{‘{’}2D{‘}’}{‘}’} &= \left(x_i \cdot \text{‘{’}scale{‘}’}_i, ; y_i \cdot \text{‘{’}scale{‘}’}_i, ; \text{‘{’}scale{‘}’}_i, ; \text{‘{’}alpha{‘}’}_i\right) \end{‘{’}aligned{‘}’}{‘}’}

Реализация на TypeScript в точности отражает эту математику:

export function project(
points: { x: number; y: number; z: number }[],
depth: number,
): ProjectedTag[] {
const d2 = 2 * depth;
return points.map((p) => {
const per = d2 / (d2 + p.z);
const alpha = Math.min(1, Math.max(0, per * per - 0.25));
return { x: p.x, y: p.y, z: p.z, scale: per, alpha };
});
}

3. Архитектура и дизайн модулей

Кодовая база является примером чистой программной архитектуры благодаря продуманному разделению математических вычислений, оркестрации рендеринга и обработки пользовательского взаимодействия.

3.1 Чистый математический движок: src/core/

Модуль Функция Вход Выход Ключевая формула
distribution.ts fibonacciSphere(n, R) N, R Vec3[] (\phi_i = \arccos(-1 + \frac{2i+1}{N}))
rotation.ts rotatePoints(points, a, b) Vec3[], a, b Vec3[] (R_y(a)) · (R_x(b)) · (P)
projection.ts project(points, depth) Vec3[], d ProjectedTag[] per = 2d/(2d+z), (\alpha) = per(^2) - 0.25

3.2 Двойная система рендеринга: Canvas + DOM

Одно из наиболее значительных нововведений — это двойная система рендеринга, использующая Canvas 2D API для текста и изображений и DOM-оверлей для SVG, HTML, видео и веб-компонентов.

flowchart TB
    subgraph "Типы тегов и рендереры"
        direction LR
        TEXT["📄 Текстовый тег"]
        IMG["🖼️ Тег-изображение"]
        SVG_TAG["🎨 SVG-тег"]
        HTML_TAG["🌐 HTML-тег"]
        VIDEO["🎬 Видео-тег"]
        ELEMENT["🔧 Тег-элемент"]
    end

    subgraph "Выбор рендерера"
        CANVAS["Canvas 2D API
✅ Текст
✅ Изображения"] DOM["DOM-оверлей
✅ SVG
✅ HTML
✅ Видео
✅ Веб-компоненты"] end TEXT --> CANVAS IMG --> CANVAS SVG_TAG --> DOM HTML_TAG --> DOM VIDEO --> DOM ELEMENT --> DOM style CANVAS fill:#0f3460,stroke:#e94560,color:#fff style DOM fill:#533483,stroke:#e94560,color:#fff

4. Характеристики производительности

4.1 Вычислительная сложность

Стадия Сложность Доминирующие операции
Поворот O(N) 8 умножений + 4 сложения на точку
Проекция O(N) 1 деление + 2 умножения + 1 сложение на точку
Z-сортировка O(N log N) Сортировка сравнением
Canvas-рендеринг O(N) fillText / drawImage вызовы
DOM-обновление O(N) transform + opacity установка

4.2 Эффективность использования памяти

Для (N = 100) меток общее числовое состояние составляет около (100 \times (3 + 5) \times 8 = 6,400) байт — менее 7KB чисел с плавающей точкой.

4.3 Размер бандла

Формат Размер
ESM (dist/index.js) ~12 KB
Gzip ~3 KB
Brotli ~2.5 KB

5. Мультимодальный контент: Шесть типов тегов

Тип тега Формат ввода Рендерер Интерактивность Сценарий использования
Текст string Canvas 2D колбэк onTagClick Навыки, ключевые слова
Изображение { type:“image”, src, w, h } Canvas 2D onClick на тег Логотипы, аватары
SVG { type:“svg”, content, w, h } DOM onClick на тег Векторные иконки
HTML { type:“html”, html } DOM onClick на тег Форматированный текст
Видео { type:“video”, src, w, h } DOM Полный экран по клику Демо-клипы
Элемент { type:“element”, element } DOM Нативные DOM-события Веб-компоненты

6. Сравнение с cong-min/TagCloud

Аспект cong-min/TagCloud @xingwangzhe/tags-cloud Улучшение
Язык JavaScript (ES5) TypeScript Полная типобезопасность
Размер бандла ~6KB минифицировано ~3KB gzip ~на 50% меньше
Зависимости 0 0 Оба без зависимостей
Типы тегов Только текст Текст, Изображение, SVG, HTML, Видео, Элемент 6x типов контента
Рендерер Только DOM Canvas 2D + DOM гибрид Лучшая производительность
Инструмент сборки Rollup + Babel Vite + Bun + Oxlint Современный инструментарий
Drag-взаимодействие Базовое мышью Arcball-стиль + инерция Более естественное ощущение
Поддержка сенсорного ввода Неявная Полная поддержка + мобильный CSS Готово для мобильных

7. Практическое руководство

7.1 Базовое текстовое облако

import { TagCloud } from "@xingwangzhe/tags-cloud";
const container = document.getElementById("cloud")!;
new TagCloud(container, {
tags: ["TypeScript", "React", "Vue", "Svelte", "Node.js", "Bun", "Rust"],
radius: 250,
spinY: 0.12,
color: "#e0e0e0",
fontSize: 16,
});

7.2 Мультимодальное облако

new TagCloud(container, {
tags: [
"TypeScript",
{ type: "image", src: "/avatar.webp", width: 40, height: 40 },
{ type: "svg", content: `<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/></svg>`, width: 48, height: 48 },
{ type: "video", src: "/demo.mp4", width: 120, height: 68 },
],
radius: 300,
spinY: 0.15,
onTagClick(item) { console.log("Clicked:", item); },
});

7.3 Управление жизненным циклом

const cloud = new TagCloud(container, { tags, spinY: 0.2 });
cloud.setTags(["New", "Set", "Of", "Tags"]);
cloud.pause();
cloud.resume();
cloud.destroy();

8. Заключение: Математика как движок рендеринга

@xingwangzhe/tags-cloud служит убедительной демонстрацией того, что самый мощный движок рендеринга в программировании — это не GPU, не компилятор шейдеров и не фреймворк, а математика. Разложив задачу визуализации 3D-облака тегов на три чистых математических операции — распределение Фибоначчи по сфере, умножение матриц поворота и перспективную проекцию, — библиотека достигает результатов, визуально неотличимых от WebGL-альтернатив, не требуя при этом ни их сложности, ни аппаратных зависимостей, ни веса бандла.

Вклад проекта в open-source экосистему троекратен. Архитектурно он доказывает, что гибридный Canvas/DOM-рендерер может обеспечивать как производительность, так и универсальность в 3KB-пакете. Математически он предлагает чистые, хорошо документированные реализации фундаментальных алгоритмов 3D-графики. Практически он даёт разработчикам готовый компонент для создания 3D-облаков тегов с поддержкой мультимедиа, типобезопасностью TypeScript и мобильной интерактивностью — и всё это без добавления единой зависимости.


Конец статьи — Основано на анализе исходного кода @xingwangzhe/tags-cloud v0.9.0

Share this page