Free, open-source app to learn Chinese characters: spaced repetition, writing practice, HSK 1-4
See the codeA free, open-source web app for learning Chinese characters and vocabulary. Spaced repetition, stroke-by-stroke writing practice, tone-colored pinyin and a full Chinese-English dictionary, in a clean interface that works on desktop and phone.
Try it: vividhanzi.com · no account needed, no ads.
VividHanzi is free and has no ads or paid tier. If it helps you learn, you can buy me a coffee on Ko-fi. Bug reports, ideas and pull requests are just as welcome.
Issues and pull requests are welcome. Read
CONTRIBUTING.md for how to set up the project, the
conventions and what to check before opening a pull request.
Requires Node.js 20.19 or later (22 recommended).
npm install
npm run dev # development server at http://localhost:5173
Without a Supabase project configured the app works the same, just without
accounts. See docs/ACCOUNTS.md.
| Command | What it does |
|---|---|
npm run dev | Development server with hot reload |
npm run build | Type-checks and builds the production version into dist/ |
npm run preview | Serves the production build locally |
npm run typecheck | Type-check only |
npm run lint | Linter (oxlint) |
npm test | Runs the tests once |
npm run test:watch | Tests in watch mode |
npm run check | Types + lint + tests (the same thing CI runs) |
npm run data:fetch | Downloads the dataset sources (HSK list, CC-CEDICT, Unihan, Make Me a Hanzi, Tatoeba) |
npm run data:build | Regenerates the dataset in src/data/, public/strokes/ and public/examples/ (see docs/DATA_SOURCES.md) |
npm run data:validate | Validates the generated dataset without downloading anything |
npm run seo:pages | After a build, writes a static page per HSK character and word, sitemap.xml and robots.txt into dist/ (needs SITE_URL; the Deploy workflow runs it) |
React 19 · TypeScript (strict) · Vite · Tailwind CSS v4 · React Router · Hanzi Writer · Supabase (optional sync) · Vitest + Testing Library · oxlint. Hosted on GitHub Pages.
docs/ Architecture, data sources, accounts and screenshots
scripts/dataset/ Script that generates the dataset from the sources
public/ Static files: icons, stroke data and example sentences for HSK
supabase/ Database schema for the optional account sync
src/
app/ App shell, routes and navigation
pages/ One page per app section
features/ Domain logic and components (practice, srs, progress, dictionary,
grammar, sync, ...); logic is plain TypeScript, tested without React
data/ Generated dataset (HSK 1-5, topic sets, grammar notes)
lib/ Domain-free utilities (pinyin, dates, storage)
components/ui/ Shared visual pieces
i18n/ Interface texts and the t() function
How it fits together is in docs/ARCHITECTURE.md.
All linguistic data comes from open sources and is generated with a script; nothing is written by hand or by AI. Thanks to the people behind them:
Details on versions and which source owns each field are in
docs/DATA_SOURCES.md.
The source code is released under the MIT License.
The linguistic data is not covered by the MIT License: each data file keeps the license of its source (see above). In particular, the word and character data derived from CC-CEDICT and wordfreq is shared under CC BY-SA 4.0, the example sentences under CC BY 2.0 FR and the stroke data under the Arphic Public License.
Free, open-source app to learn Chinese characters: spaced repetition, writing practice, HSK 1-4
See the codeA free, open-source web app for learning Chinese characters and vocabulary. Spaced repetition, stroke-by-stroke writing practice, tone-colored pinyin and a full Chinese-English dictionary, in a clean interface that works on desktop and phone.
Try it: vividhanzi.com · no account needed, no ads.
VividHanzi is free and has no ads or paid tier. If it helps you learn, you can buy me a coffee on Ko-fi. Bug reports, ideas and pull requests are just as welcome.
Issues and pull requests are welcome. Read
CONTRIBUTING.md for how to set up the project, the
conventions and what to check before opening a pull request.
Requires Node.js 20.19 or later (22 recommended).
npm install
npm run dev # development server at http://localhost:5173
Without a Supabase project configured the app works the same, just without
accounts. See docs/ACCOUNTS.md.
| Command | What it does |
|---|---|
npm run dev | Development server with hot reload |
npm run build | Type-checks and builds the production version into dist/ |
npm run preview | Serves the production build locally |
npm run typecheck | Type-check only |
npm run lint | Linter (oxlint) |
npm test | Runs the tests once |
npm run test:watch | Tests in watch mode |
npm run check | Types + lint + tests (the same thing CI runs) |
npm run data:fetch | Downloads the dataset sources (HSK list, CC-CEDICT, Unihan, Make Me a Hanzi, Tatoeba) |
npm run data:build | Regenerates the dataset in src/data/, public/strokes/ and public/examples/ (see docs/DATA_SOURCES.md) |
npm run data:validate | Validates the generated dataset without downloading anything |
npm run seo:pages | After a build, writes a static page per HSK character and word, sitemap.xml and robots.txt into dist/ (needs SITE_URL; the Deploy workflow runs it) |
React 19 · TypeScript (strict) · Vite · Tailwind CSS v4 · React Router · Hanzi Writer · Supabase (optional sync) · Vitest + Testing Library · oxlint. Hosted on GitHub Pages.
docs/ Architecture, data sources, accounts and screenshots
scripts/dataset/ Script that generates the dataset from the sources
public/ Static files: icons, stroke data and example sentences for HSK
supabase/ Database schema for the optional account sync
src/
app/ App shell, routes and navigation
pages/ One page per app section
features/ Domain logic and components (practice, srs, progress, dictionary,
grammar, sync, ...); logic is plain TypeScript, tested without React
data/ Generated dataset (HSK 1-5, topic sets, grammar notes)
lib/ Domain-free utilities (pinyin, dates, storage)
components/ui/ Shared visual pieces
i18n/ Interface texts and the t() function
How it fits together is in docs/ARCHITECTURE.md.
All linguistic data comes from open sources and is generated with a script; nothing is written by hand or by AI. Thanks to the people behind them:
Details on versions and which source owns each field are in
docs/DATA_SOURCES.md.
The source code is released under the MIT License.
The linguistic data is not covered by the MIT License: each data file keeps the license of its source (see above). In particular, the word and character data derived from CC-CEDICT and wordfreq is shared under CC BY-SA 4.0, the example sentences under CC BY 2.0 FR and the stroke data under the Arphic Public License.