A lightweight, dependency-free JavaScript library for Kanji stroke order recognition and validation using KanjiVG data.
- ๐ฏ Accurate Recognition - Uses geometric resampling algorithm with centroid-based alignment for robust recognition
- ๐ Multiple Modes - Supports Stroke-by-Stroke validation, Full Kanji check, and Free Write
- ๐ผ๏ธ Image Export - Export your drawings as PNG images for AI analysis or saving
- ๐จ Fully Customizable - Easy to style colors, animations, and recognition sensitivity
- โก Lightweight - Zero dependencies, pure SVG-based rendering
- ๐ฑ Mobile-Friendly - Touch-optimized with pointer events
- ๐ Browser Compatible - Works in Chrome, Firefox, Safari, and Edge
npm install kanji-recognizerOr use directly in browser:
<script type="module">
import { KanjiWriter, KanjiVGParser } from './kanji-recognizer/src/index.js';
</script>import { KanjiWriter, KanjiVGParser } from 'kanji-recognizer';
// 1. Fetch kanji data from KanjiVG
const kanjiData = await KanjiVGParser.fetchData('ๆฅ');
// 2. Create a writer instance
const writer = new KanjiWriter('container-id', kanjiData, {
width: 300,
height: 300
});
// 3. Listen for events
writer.onCorrect = () => console.log("Correct stroke!");
writer.onComplete = () => console.log("Kanji complete!");Creates an interactive kanji writing canvas.
const writer = new KanjiWriter(elementId, kanjiData, options);- elementId
string- DOM element ID to mount the canvas - kanjiData
string[]- Array of SVG path strings from KanjiVG - options
object- Configuration options (optional)
{
// Dimensions
width: 300, // Canvas width in pixels
height: 300, // Canvas height in pixels
// Colors
strokeColor: '#333', // Main stroke color
correctColor: '#4CAF50', // Success feedback color
incorrectColor: '#F44336', // Error feedback color
hintColor: 'cyan', // Hint animation color
gridColor: '#ddd', // Background grid color
ghostColor: '#ff0000', // Next stroke guide color
// Appearance
strokeWidth: 4, // Width of drawn strokes
gridWidth: 0.5, // Grid line width
ghostOpacity: '0.1', // Ghost guide opacity
// Behavior
showGhost: true, // Show red guide for next stroke
showGrid: true, // Show background grid
checkMode: 'stroke', // 'stroke' (immediate), 'full' (manual), or 'free' (no validation)
// Recognition (Adjustable!)
passThreshold: 15, // Lower = stricter (10-20 recommended)
startDistThreshold: 40, // Start point tolerance in pixels
lengthRatioMin: 0.5, // Minimum stroke length ratio
lengthRatioMax: 1.5, // Maximum stroke length ratio
// Animations
stepDuration: 500, // Animation speed in ms
hintDuration: 800, // Hint display duration
snapDuration: 200 // Snap-to-correct duration
}Reset the canvas and start over.
writer.clear();Show animated hint for the next expected stroke.
writer.hint();Animate the complete kanji stroke-by-stroke.
await writer.animate();Update configuration options dynamically.
writer.setOptions({
strokeColor: '#000',
passThreshold: 20 // Make recognition more lenient
});Clean up resources and remove event listeners.
writer.destroy();Export the current drawing as a base64 PNG image.
const dataUrl = await writer.exportImage({
includeGrid: false,
backgroundColor: '#ffffff'
});
// Send dataUrl to AI or save itManually trigger evaluation of all collected strokes (only for checkMode: 'full').
const result = writer.check();
if (result.success) console.log("All strokes correct!");writer.onCorrect = () => { /* Fired on correct stroke */ };
writer.onIncorrect = () => { /* Fired on incorrect stroke */ };
writer.onComplete = () => { /* Fired when kanji is complete */ };
writer.onClear = () => { /* Fired when canvas is cleared */ };
// Error handling
writer.container.addEventListener('kanji:error', (e) => {
console.error('Error:', e.detail);
});Utilities for fetching and parsing KanjiVG SVG data.
Fetch kanji stroke data by character.
const strokes = await KanjiVGParser.fetchData('ๆฅ');
// Returns: ['M25,32...', 'M12,80...']Parse raw KanjiVG SVG into stroke paths.
const strokes = KanjiVGParser.parse(svgString);Set custom base URL for KanjiVG files.
KanjiVGParser.baseUrl = 'https://example.com/kanjivg/';import { KanjiWriter, KanjiVGParser } from 'kanji-recognizer';
// Load kanji
const kanjiData = await KanjiVGParser.fetchData('ๆ');
// Create writer
const writer = new KanjiWriter('practice-area', kanjiData);
// Add event listeners
writer.onCorrect = () => {
document.getElementById('feedback').textContent = 'ๆญฃ่งฃ๏ผ';
};
writer.onComplete = () => {
document.getElementById('feedback').textContent = 'ๅฎๆ๏ผ';
confetti(); // Celebrate!
};const writer = new KanjiWriter('container', kanjiData, {
passThreshold: 20, // More forgiving
startDistThreshold: 50, // Allow imprecise starts
showGhost: true, // Show guides
hintColor: '#00ff00' // Bright hints
});const writer = new KanjiWriter('container', kanjiData, {
passThreshold: 8, // Very strict
startDistThreshold: 25, // Precise starts required
showGhost: false, // No guides
strokeColor: '#000' // Professional look
});const writer = new KanjiWriter('container', kanjiData, {
width: 500,
height: 500,
strokeColor: '#2c3e50',
correctColor: '#27ae60',
incorrectColor: '#e74c3c',
gridColor: '#ecf0f1',
strokeWidth: 6
});const kanjis = ['ๆฅ', 'ๆ', '็ซ', 'ๆฐด', 'ๆจ', '้', 'ๅ'];
let currentIndex = 0;
async function nextKanji() {
if (writer) writer.destroy(); // Clean up previous
const data = await KanjiVGParser.fetchData(kanjis[currentIndex]);
writer = new KanjiWriter('container', data);
writer.onComplete = () => {
currentIndex++;
if (currentIndex < kanjis.length) {
setTimeout(nextKanji, 1000);
}
};
}
nextKanji();Check out the included demo:
cd kanji-recognizer
python3 -m http.server 8000
# Open http://localhost:8000/demo/index.html- Modern browser with ES6 module support
- KanjiVG SVG files (not included in npm package)
Download from KanjiVG Project:
git clone https://github.com/KanjiVG/kanjivg.gitOr use a CDN:
KanjiVGParser.baseUrl = 'https://cdn.example.com/kanjivg/';- Chrome/Edge: โ Latest
- Firefox: โ Latest
- Safari: โ 14+
- Safari iOS: โ 14+
- Chrome Mobile: โ Latest
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
See docs/README_REVIEW.md for development documentation.
This project is licensed under the MIT License - see the LICENSE file for details.
- KanjiVG - Kanji stroke order data
- Inspired by Japanese language learning tools
- KanjiVG - Kanji stroke order graphics
- kanji-data - Comprehensive kanji dataset
- None currently! Report issues on GitHub
- TypeScript definitions
- React component wrapper
- Vue component wrapper
- Bundled common kanji data
- Offline support with Service Worker
- Haptic feedback for mobile
- Audio pronunciation integration
- ๐ Issues: GitHub Issues
- ๐ฌ Discussions: GitHub Discussions
Made with โค๏ธ for Japanese learners worldwide