Interactive Demo
Word clouds that feel native to D3
Type words below, tune the layout in real time, and watch the cloud animate its placement. Built on a persistent bitmap board with incremental streaming, promise-friendly async, and full D3 selection rendering.
ESM-first
Incremental streaming
Async / await
Bitmap collision
D3 selection rendering
Words Placed
0
in the cloud
Footprint
—
layout bounds
Largest Word
0px
font size
Coverage
0%
of canvas area
Word Manager
Weight controls font size (1–200). Press Enter to add.
Quick presets
Active preset drives the Stream Lab and Spiral Comparison.
Words (0)
Add words above to get started
Add words to see the cloud
Layout
Spiral
Rotation Mixed
Padding 3
Typography
Min size 14px
Max size 80px
Font
Color Palette
Scheme
Custom colors
Feature
Incremental Streaming Lab
Words arrive one burst at a time. Existing words never move — new placements integrate into the live board.
Total placed
0
Last burst
0
Board bounds
—
Recent arrivals
≈0 words/s
No arrivals yet
How it works
Each addAsync(batch) call places a new batch into the same persistent bitmap board.
Existing words are never disturbed — the algorithm only searches free space beyond the current boundary for incoming words.
Feature
Spiral Comparison
Same data, same seed — only the search geometry differs. Archimedean is smoother; Rectangular has sharper steps.
Archimedean Spiral
Smooth radial search · balanced packing
Rectangular Spiral
Axial steps · tighter rectangular packing
Feature
Minimal update — add duplicate or remove
Adding a word that already exists boosts its weight and triggers a fresh placement pass.
The transitions keep that update readable, but the cloud may re-pack around the changed word.
Try it
Click a word chip to add it again (+20 weight). Click any word in the cloud to remove it.
Add duplicates
Event log
API & Features
Three lines to a cloud.
The library surface is intentionally small. Everything you need, nothing you don't.
import { cloud, renderWords } from "d3-wordcloud";
import * as d3 from "d3";
// Build the layout
const layout = cloud()
.size([960, 560])
.words(words)
.fontSize((d) => scale(d.value))
.padding(3)
.spiral("archimedean");
// Await the result
const { words, bounds } = await layout.startAsync();
// Render with D3
renderWords(svg, words, {
width, height,
fill: (d) => color(d.group),
title: (d) => `${d.text}: ${d.value}`,
});
// Incremental streaming — board persists!
await layout.addAsync(newBatch);Bitmap collision
Pixel-perfect placement using Jonathan Feinberg's bitmask algorithm. No overlapping words, ever.
Incremental add
addAsync() extends the live board. Existing words never shift or re-render.Promise API
startAsync() and addAsync() return promises — works naturally with async/await.renderWords()
Drop-in D3 data join helper. Bring your own colors, fonts, classes, and transitions.
Dual spirals
Archimedean for radial smoothness, Rectangular for tighter axis-aligned fills.
ESM-first
Tree-shakeable ES module with a UMD fallback. Zero runtime dependencies beyond d3-dispatch.