An interactive visual sandbox for exploring how Japanese Kanji are built from radicals. Start with a basic radical, evolve it into Kanji, and watch an evolution tree grow on an infinite canvas.
Live → honsda.github.io/kmap
Japanese Kanji are made up of smaller building blocks called radicals. For example, the kanji 明 (bright) is composed of 日 (sun) and 月 (moon).
kmap lets you explore these relationships visually:
- Start with a radical — drop one onto the canvas.
- Evolve it — the app finds Kanji that contain your radical and places them as connected nodes.
- Keep branching — each new Kanji can evolve further, forming a tree of increasingly complex characters.
The result is a node graph that shows how simple strokes combine into the thousands of characters used in written Japanese.
| Action | Input |
|---|---|
| Pan the canvas | Click and drag on empty space |
| Zoom in / out | Scroll wheel |
| Move a block | Click and drag it |
| Delete a block | Hover over it, click the 除 button |
| Button | What it does |
|---|---|
| JLPT filter | Vertical level selector (N5–N1). Selecting a level limits all random generation to Kanji at that level or easier. Kanji without an official JLPT rating are always included. |
| + (red) | Opens a modal to manually pick a radical from the full list. |
| 部 | Adds a random radical to the canvas as a new root node. |
| 字 | Picks a random Kanji that uses a radical already on the canvas and adds it as a connected node. |
| ⟳ | Clears the entire canvas. |
Hover over any block to reveal a floating action menu:
- ℹ — Open the detail sidebar with readings, meanings, JLPT level, constituent radicals, related Kanji (synonyms), and example words.
- + — Open the combination modal showing every Kanji that can be formed from this radical/kanji, filterable by JLPT level.
- ⇡ — Evolve this block into a more complex Kanji that contains its radicals (random pick).
- 字 — Add a random Kanji that uses this block's radical.
Click any block to open the right-hand sidebar, which shows:
- Onyomi / Kunyomi readings with Romaji transliteration
- JLPT level badge
- Constituent radicals — every radical that makes up the selected Kanji
- Related Kanji (Synonyms) — other Kanji with similar English meanings, clickable to add them as standalone blocks
- Word examples — common vocabulary using the Kanji, with Japanese example sentences and English translations
- Common Kanji — all Kanji that share this radical, clickable to branch from the current node
When a Kanji block is connected to a parent, small badges appear at the bottom showing only the new radicals that were added compared to the parent. This makes it easy to see what changed at each evolution step.
Arrows connect parent blocks to their children. Straight (horizontal/vertical) arrows sit tightly between adjacent boxes, while diagonal arrows have slightly more margin for readability.
| Layer | Technology |
|---|---|
| Framework | Astro (static site generation) |
| UI | Svelte 5 (runes, reactive state) |
| Styling | Tailwind CSS v4 |
| Readings | wanakana (kana ↔ romaji) |
| Synonyms | Datamuse API |
| Word examples | kanjiapi.dev |
The build script (scripts/build-radical-data.cjs) fetches and merges data from:
- KANJIDIC2 — readings, meanings, stroke counts, JLPT levels for 13,000+ characters
- KanjiVG — radical decomposition mappings (which radicals make up which Kanji)
- Kanji Alive — radical names and meanings
- kanji-data — supplemental JLPT level data
- Unicode EquivalentUnifiedIdeograph — normalizes Kangxi radical codepoints to standard CJK
All data is processed at build time into static JSON files. No database required.
Requires Node.js ≥ 22.12.0.
# Install dependencies
npm install
# Start dev server (builds data + starts Astro)
npm run dev
# Production build
npm run build
# Preview production build
npm run previewsrc/
├── components/
│ ├── SandboxGrid.svelte # Main canvas with pan/zoom and arrow rendering
│ ├── RadicalBlock.svelte # Individual node (radical or kanji block)
│ ├── FloatingMenu.svelte # Hover action buttons on each block
│ ├── Tooltip.svelte # Hover tooltip with quick info
│ ├── DetailedInfoModal.svelte # Right sidebar with full kanji details
│ ├── CombinationModal.svelte # Modal listing all possible kanji combinations
│ └── RadicalSelectorModal.svelte # Modal for manually picking a radical
├── stores/
│ └── gridStore.js # Central state: grid blocks, evolution logic, JLPT filter
├── layouts/
│ └── Layout.astro # HTML shell with metadata
└── pages/
└── index.astro # Entry point, loads data and renders SandboxGrid
scripts/
└── build-radical-data.cjs # Fetches and merges kanji dictionaries into static JSON
public/data/
├── radical_data.json # Radical → meanings, readings, common kanji
├── radical_list.json # Ordered list of all radicals
└── kanji_data.json # Kanji → readings, meanings, JLPT, radicals
Pushes to main automatically deploy to GitHub Pages via the workflow in .github/workflows/deploy.yml.
MIT