@xingwangzhe/tags-cloud: The Multi-Modal 3D Tag Cloud Engine Built on Pure Mathematics
@xingwangzhe/tags-cloud: The Multi-Modal 3D Tag Cloud Engine Built on Pure Mathematics
GitHub: xingwangzhe/tags-cloud · Demo: tagscloud.needhelp.icu · npm: @xingwangzhe/tags-cloud · License: MIT · Version: v0.9.0
1. Introduction: Reimagining the 3D Tag Cloud for the Modern Web
The tag cloud has been a staple of web visualization for over two decades, evolving from simple weighted word lists into immersive three-dimensional experiences that captivate users and transform mundane text collections into interactive spatial sculptures. Among the most influential contributions to this evolution is cong-min/TagCloud, a lightweight JavaScript library that demonstrated how a sphere of rotating text labels could be achieved with minimal overhead and zero external dependencies. With 390 stars and 93 forks on GitHub, the original TagCloud established a design pattern that countless developers have adopted for portfolio sites, skill showcases, and data visualization dashboards. Its core innovation lay in proving that 3D tag clouds need not rely on heavyweight WebGL frameworks or external rendering engines; instead, straightforward trigonometric calculations combined with careful DOM positioning could produce surprisingly compelling visual results.
Enter @xingwangzhe/tags-cloud — a ground-up reimagining of the 3D tag cloud concept that preserves the mathematical elegance of its predecessor while dramatically expanding its capabilities, modernizing its architecture, and pushing the boundaries of what a tag cloud can render. This is not merely a fork or a feature addition; it represents a fundamental architectural shift from a text-only, DOM-heavy renderer to a multi-modal engine capable of displaying text, images, SVG graphics, arbitrary HTML, video elements, and even full Web Components — all rotating together in a mathematically precise three-dimensional space. The library achieves this versatility while maintaining an extraordinarily compact footprint of approximately 3KB gzipped, carrying zero runtime dependencies, and being built with a thoroughly modern toolchain comprising Bun as the JavaScript runtime, Vite as the bundler, and TypeScript for complete type safety throughout the entire codebase.
The project’s tagline — “multi-modal 3D tag cloud · pure math engine” — encapsulates its dual identity. On one hand, it is a practical UI component library that developers can drop into any web project to create visually striking tag spheres. On the other hand, it is a mathematical engine that decomposes the complex problem of 3D tag cloud rendering into three pure, deterministic, and beautifully separable geometric operations: Fibonacci sphere distribution for initial positioning, rotation matrix multiplication for spatial transformation, and perspective projection for depth-aware 2D rendering. Each of these operations is implemented in its own dedicated module within the src/core/ directory, making the codebase not only highly maintainable but also an excellent educational resource for anyone seeking to understand the mathematics behind 3D computer graphics without the obscuring complexity of a full rendering pipeline.
The following sections provide a comprehensive technical deep-dive into every aspect of @xingwangzhe/tags-cloud, from the golden-ratio-derived sphere distribution algorithm to the quaternion-inspired arcball interaction model, from the dual Canvas/DOM rendering architecture to the responsive design considerations that make it work seamlessly across desktop and mobile devices. Whether you are a developer evaluating this library for your next project, a graphics programmer interested in lightweight 3D techniques, or a mathematician curious about the real-world applications of the Fibonacci lattice, this article offers detailed explanations, mathematical derivations, architectural diagrams, and annotated code examples to illuminate every facet of this remarkable piece of software engineering.
2. The Mathematical Foundation: Three Pillars of 3D Rendering
At the heart of @xingwangzhe/tags-cloud lies a trio of mathematical operations that, when composed, transform an abstract list of content items into a visually coherent rotating sphere. These operations — distribution, rotation, and projection — are implemented in three dedicated modules under src/core/, each responsible for a single geometric transformation. This separation of concerns is not merely an architectural preference; it reflects the fundamental structure of 3D computer graphics pipelines, where vertex generation, model transformation, and camera projection are distinct stages that can be independently optimized, tested, and understood.
flowchart LR
subgraph Input["📥 Input Layer"]
TAGS["TagItem[]
(text | image | SVG | HTML | video | element)"]
OPTS["TagCloudOptions
(radius, spin, colors, callbacks)"]
end
subgraph CoreEngine["⚙️ Pure Math Engine (src/core/)"]
direction TB
DIST["🔵 distribution.ts
Fibonacci Sphere
N points → 3D coordinates"]
ROT["🟢 rotation.ts
Rotation Matrices
3D points → rotated 3D points"]
PROJ["🔴 projection.ts
Perspective Projection
rotated 3D → 2D + depth"]
end
subgraph RenderLayer["🎨 Render Layer"]
direction TB
CANVAS["Canvas 2D API
(text + images)"]
DOM["DOM Overlay
(SVG + HTML + video + elements)"]
end
subgraph Interaction["👤 Interaction Layer"]
MOUSE["Mouse / Touch Drag"]
INERTIA["Inertia Decay
(0.96/frame)"]
end
TAGS --> DIST
OPTS --> DIST
DIST -->|"Vec3[]"| ROT
ROT -->|"Rotated Vec3[]"| PROJ
PROJ -->|"ProjectedTag[]
(x, y, z, scale, alpha)"| CANVAS
PROJ --> DOM
MOUSE --> INERTIA
INERTIA -->|"rotation angles"| 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 Fibonacci Sphere Distribution: The Golden Geometry of Point Placement
The first and arguably most aesthetically critical step in creating a 3D tag cloud is determining where each tag should be positioned on the sphere. A naive approach might place tags at regular latitude and longitude intervals, but this inevitably leads to clustering at the poles, where meridian lines converge, and sparse regions near the equator. The Fibonacci sphere algorithm solves this problem elegantly by producing a distribution of points that is remarkably uniform across the entire sphere surface, with no visible clustering or gaps regardless of the number of points.
This algorithm draws its name from the golden ratio (\varphi = \frac{1 + \sqrt{5}}{2} \approx 1.6180339887), a mathematical constant that appears throughout nature in structures ranging from sunflower seed arrangements to nautilus shell spirals. The connection to Fibonacci numbers — the sequence where each term is the sum of the two preceding ones — is that the ratio of consecutive Fibonacci numbers converges to the golden ratio as the sequence progresses. In the context of sphere distribution, the golden ratio’s irrationality ensures that successive points are always placed at angles that never repeat, creating an aperiodic spiral pattern that fills the sphere surface evenly.
The specific implementation in src/core/distribution.ts uses a variation of the Fibonacci lattice that has been optimized for spherical mapping. For a sphere of radius (R) with (N) points to distribute, the algorithm computes the spherical coordinates and then converts them to Cartesian coordinates ((x, y, z)) for each point (i \in {0, 1, 2, \ldots, N-1}). The latitude angle (\phi) (measured from the positive z-axis, i.e., the North pole) is computed using the inverse cosine function to ensure uniform distribution along the z-axis:
This formula places the first point slightly below the North pole and the last point slightly above the South pole, with the (+0.5) offset (embedded in the (2i + 1) numerator) ensuring that no point ever lands exactly on a pole. This subtle adjustment is crucial because it prevents the visual artifact of a tag sitting directly at the top or bottom of the sphere where rotation would be barely perceptible. The (\arccos) function transforms a uniformly distributed linear parameter into a cosine-weighted angular distribution, which compensates for the fact that spheres have less surface area near the poles and more near the equator.
The longitude angle (\theta) (measured in the xy-plane from the positive x-axis) is computed using a scaling of (\phi) by (\sqrt{N\pi}), which creates the characteristic spiral pattern:
The factor (\sqrt{N\pi}) is derived from the relationship between the golden angle and the total surface area of the sphere. As (N) increases, this scaling ensures that the spiral winds around the sphere the appropriate number of times to maintain uniform spacing between neighboring points. The result is a pattern where each successive point is rotated by approximately the golden angle (\approx 137.5°) relative to its predecessor when viewed along the z-axis, mirroring the phyllotactic spirals found in nature.
Finally, these spherical coordinates are converted to Cartesian coordinates using the standard transformation:
The resulting points satisfy the sphere equation (x_i^2 + y_i^2 + z_i^2 = R^2) and are distributed with a uniformity that rivals much more computationally expensive optimization-based methods. The following display summarizes the complete Fibonacci sphere algorithm:
The TypeScript implementation in src/core/distribution.ts is remarkably concise, reflecting the algorithm’s elegant simplicity:
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;}This function returns an array of Vec3 objects that serve as the initial positions for all tags in the cloud. The algorithm runs in (\mathcal{O}(N)) time, making it suitable for tag clouds with hundreds of elements. In practice, most tag clouds contain between 20 and 100 tags, for which this computation is virtually instantaneous.
2.2 3D Rotation: Matrix Multiplication in the Spatial Domain
Once tags are positioned on the sphere surface, the next step is to enable rotation — both the continuous automatic spin and the user-driven drag interaction. The library implements rotation using composite axis-aligned rotation matrices, specifically sequential rotations around the Y-axis followed by the X-axis. This approach is computationally efficient, easy to understand, and entirely sufficient for the tag cloud use case where rotations are always relative to a sphere centered at the origin.
The mathematical foundation for these rotations comes from linear algebra. A 3D rotation matrix is a (3 \times 3) orthogonal matrix with determinant 1 that transforms the coordinates of a point while preserving its distance from the origin. For rotation by an angle (\alpha) around the Y-axis, the rotation matrix (R_y(\alpha)) is:
For rotation by an angle (\beta) around the X-axis, the rotation matrix (R_x(\beta)) is:
The library applies these rotations sequentially: first the Y-axis rotation, then the X-axis rotation. For a point (P = (x, y, z)), the Y-axis rotation produces an intermediate point (P’):
The X-axis rotation is then applied to (P’) to produce the final rotated point (P’’):
The implementation in src/core/rotation.ts expands these matrix multiplications into direct arithmetic operations, avoiding the overhead of matrix object allocation and multiplication. For a single point, the rotation function computes:
The rotatePoints function performs this transformation in batch for all tags:
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 Perspective Projection: From 3D Space to the 2D Screen
The final mathematical operation transforms the rotated 3D coordinates into 2D screen positions. The library uses a simplified but highly effective projection model that computes a scale factor and an opacity factor based on depth, with a perspective depth parameter equal to twice the sphere radius:
The opacity (alpha) factor uses a quadratic relationship with a bias adjustment:
The complete projection pipeline is summarized as:
The TypeScript implementation mirrors this mathematics precisely:
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. Architecture and Module Design
The codebase exemplifies clean software architecture through deliberate separation of mathematical computation, rendering orchestration, and user interaction handling.
3.1 The Pure Math Engine: src/core/
| Module | Function | Input | Output | Key Formula |
|---|---|---|---|---|
| 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 The Dual Rendering System: Canvas + DOM
One of the most significant innovations is its dual rendering system, using Canvas 2D API for text and images, and DOM overlay for SVG, HTML, video, and Web Components.
flowchart TB
subgraph "Tag Types & Renderers"
direction LR
TEXT["📄 Text Tag"]
IMG["🖼️ Image Tag"]
SVG_TAG["🎨 SVG Tag"]
HTML_TAG["🌐 HTML Tag"]
VIDEO["🎬 Video Tag"]
ELEMENT["🔧 Element Tag"]
end
subgraph "Renderer Selection"
CANVAS["Canvas 2D API
✅ Text
✅ Images"]
DOM["DOM Overlay
✅ SVG
✅ HTML
✅ Video
✅ Web Components"]
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. Performance Characteristics
4.1 Computational Complexity
| Stage | Complexity | Dominant Operations |
|---|---|---|
| Rotation | O(N) | 8 muls + 4 adds per point |
| Projection | O(N) | 1 div + 2 muls + 1 add per point |
| Z-sort | O(N log N) | Comparison-based sort |
| Canvas Render | O(N) | fillText / drawImage calls |
| DOM Update | O(N) | transform + opacity set |
4.2 Memory Efficiency
For (N = 100) tags, total numeric state is about (100 \times (3 + 5) \times 8 = 6,400) bytes — less than 7KB of floating-point numbers.
4.3 Bundle Size
| Format | Size |
|---|---|
| ESM (dist/index.js) | ~12 KB |
| Gzip | ~3 KB |
| Brotli | ~2.5 KB |
5. Multi-Modal Content: Six Tag Types
| Tag Type | Input Format | Renderer | Interactivity | Use Case |
|---|---|---|---|---|
| Text | string | Canvas 2D | onTagClick callback | Skills, keywords |
| Image | { type:“image”, src, w, h } | Canvas 2D | onClick per tag | Logos, avatars |
| SVG | { type:“svg”, content, w, h } | DOM | onClick per tag | Vector icons |
| HTML | { type:“html”, html } | DOM | onClick per tag | Rich formatted text |
| Video | { type:“video”, src, w, h } | DOM | Fullscreen on click | Demo clips |
| Element | { type:“element”, element } | DOM | Native DOM events | Web Components |
6. Comparison with cong-min/TagCloud
| Aspect | cong-min/TagCloud | @xingwangzhe/tags-cloud | Improvement |
|---|---|---|---|
| Language | JavaScript (ES5) | TypeScript | Full type safety |
| Bundle Size | ~6KB minified | ~3KB gzipped | ~50% smaller |
| Dependencies | 0 | 0 | Both dependency-free |
| Tag Types | Text only | Text, Image, SVG, HTML, Video, Element | 6x content modalities |
| Renderer | DOM only | Canvas 2D + DOM hybrid | Better performance |
| Build Tool | Rollup + Babel | Vite + Bun + Oxlint | Modern toolchain |
| Drag Interaction | Basic mouse drag | Arcball-style + inertia | More natural feel |
| Touch Support | Not explicit | Full touch + mobile CSS | Mobile-ready |
7. Practical Usage Guide
7.1 Basic Text-Only Cloud
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 Multi-Modal Cloud
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 Lifecycle Management
const cloud = new TagCloud(container, { tags, spinY: 0.2 });cloud.setTags(["New", "Set", "Of", "Tags"]);cloud.pause();cloud.resume();cloud.destroy();8. Conclusion: Mathematics as the Rendering Engine
@xingwangzhe/tags-cloud stands as a compelling demonstration that the most powerful rendering engine in software is not a GPU, a shader compiler, or a framework — it is mathematics. By decomposing the problem of 3D tag cloud visualization into three pure mathematical operations — Fibonacci sphere distribution, rotation matrix multiplication, and perspective projection — the library achieves results that are visually indistinguishable from WebGL-based alternatives while requiring none of their complexity, hardware dependencies, or bundle weight.
The project’s contributions to the open-source ecosystem are threefold. Architecturally, it proves that a hybrid Canvas/DOM renderer can deliver both performance and versatility within a 3KB package. Mathematically, it provides clean, well-documented implementations of fundamental 3D graphics algorithms. Practically, it gives developers a drop-in component for creating 3D tag clouds with rich media support, TypeScript safety, and mobile-ready interaction — all without adding a single dependency.
End of Article — Based on source code analysis of @xingwangzhe/tags-cloud v0.9.0