@kaspars/kaku-ren
v1.3.0
Published
CJK character stroke practice with drawing input and evaluation
Maintainers
Readme
Kaku Ren (画練)
A stroke practice library for building Japanese and Chinese character study tools. Captures user drawing input on a canvas overlay and evaluates stroke accuracy against expected strokes from @kaspars/kaku.
The name comes from the Japanese 画練 — 画 (kaku, stroke) combined with 練 (ren, practice). Where Kaku animates strokes, Kaku Ren lets you practice writing them.
Installation
npm install @kaspars/kaku-ren @kaspars/kakuOverview
Kaku Ren adds interactive stroke practice on top of Kaku's animation engine:
- Displays a canvas overlay on top of the Kaku SVG
- Captures mouse/touch/pointer input as the user draws strokes
- Evaluates each stroke against the expected path (shape, length, direction)
- Morphs accepted strokes into the correct form
- Shows animated hints on incorrect attempts (draw animation in hint color)
Quick Start
import { Kaku, KanjiVGProvider } from '@kaspars/kaku';
import { KakuRen } from '@kaspars/kaku-ren';
const provider = new KanjiVGProvider({
basePath: 'https://raw.githubusercontent.com/KanjiVG/kanjivg/master/kanji'
});
const container = document.getElementById('canvas');
const kaku = new Kaku({
provider,
container,
size: 200,
showOutline: true, // Show faint character outline
});
const ren = new KakuRen({
kaku,
container,
size: 200,
strokeColor: '#333',
hintColor: '#c44',
onAccept(index, result) {
console.log(`Stroke ${index + 1} accepted (${Math.round(result.score * 100)}%)`);
},
onReject(index, result) {
console.log(`Stroke ${index + 1} rejected: ${result.rejection}`);
},
onComplete(averageScore) {
console.log(`Done! Average score: ${Math.round(averageScore * 100)}%`);
},
});
await kaku.load('漢');Works with both KanjiVG and AnimCJK providers — pass the appropriate Kaku instance.
API
Constructor Options
interface KakuRenOptions {
kaku: Kaku; // Kaku instance (required)
container: HTMLElement; // Container element (required)
size?: number; // Canvas size in CSS pixels (default: 200)
strokeColor?: string; // Drawing stroke color (default: '#333')
strokeWidth?: number; // Drawing stroke width (auto-computed if omitted)
hintColor?: string; // Hint stroke color on rejection (default: '#c44')
hintDuration?: number; // Hint draw animation duration in seconds (default: 0.6)
morphDuration?: number; // Morph animation duration in ms (default: 80)
evaluation?: EvaluatorOptions; // Evaluation tuning
onAccept?: (index: number, result: EvaluationResult) => void;
onReject?: (index: number, result: EvaluationResult) => void;
onComplete?: (averageScore: number) => void;
}Properties
| Property | Type | Description |
|----------|------|-------------|
| currentStroke | number | Current stroke index |
| totalStrokes | number | Total number of strokes |
| averageScore | number | Average score across all strokes |
| allScores | readonly number[] | All scores so far |
| enabled | boolean | Enable/disable drawing input |
Methods
| Method | Description |
|--------|-------------|
| reset(): void | Reset practice state (scores and strokes) |
| refresh(): void | Refresh overlay after loading a new character |
| dispose(): void | Clean up resources |
EvaluationResult
interface EvaluationResult {
accepted: boolean;
score: number; // 0-1, higher is better
rejection?: 'too-short' | 'wrong-direction' | 'low-score';
}Credits
Stroke data is provided by KanjiVG (CC BY-SA 3.0) and AnimCJK (Arphic PL / LGPL). See the @kaspars/kaku README for details.
License
MIT
