Shuangpin practice: a browser trainer for the double-pinyin input method
纸砚双拼,可能是最好用的双拼练习工具,支持声母 / 韵母 / 长句模式、自定义双拼方案、进度统计、深色模式、成就系统。
At a glance
- What is it?
- Shuangpin is a Vue web application for learning to type in Chinese with a double-pinyin keyboard layout, where each key stands for two syllables and the layout has to be memorised as a mapping rather than as a table of characters. The tool trains that mapping in four modes, from random syllables to whole sentences, and keeps a progress record and an achievement system so the practice does not turn into a dull repetition exercise.
- Who is it for?
- Adopt Shuangpin if you are learning a Chinese double-pinyin layout and want something more structured than reading a chart, since the four modes drill the mapping in a sensible order and the progress statistics and achievements give a reason to come back. Do not expect an input method, because it is a browser practice tool with no system integration, and do not treat the achievement system as a finished feature since the README marks it as work in progress.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 7 days ago.
- What is it written in?
- Mainly Vue, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the tool is for
The repository is a browser application for practising shuangpin, which is the Chinese term for a double-pinyin input method, and the description calls it possibly the best double-pinyin practice tool available, supporting consonant, vowel and long-sentence modes, custom layouts, progress statistics, a dark mode and an achievement system.
The problem it addresses is worth stating for anyone who does not read Chinese. Typing Chinese with pinyin means typing a full syllable such as ni3 or hao3 and then choosing the right character from a list of candidates, which is slow for a practised typist but requires no memorisation to start. A double-pinyin layout compresses that: each physical key carries two syllables, so a full Chinese syllable is two keystrokes, and the layout is a fixed mapping from letters to syllables.
That speed comes at the cost of having to learn the mapping, and the mapping is the awkward part. It is a two-way association: the letter q means iu in one scheme and means u in another, and there are several such collisions. Nobody wants to look up a chart, so the tool exists to drill the association until it becomes reflex.
The application itself is a single-page Vue app served as static files, with the live site at shuangpin.simplenaive.cn and the source in the repository. The primary language is Vue, the licence is MIT with the Anti 996 License as a supplementary term, the default branch is main, and the last push was on 2026-10-16 with the project not archived. The repository publishes no GitHub releases, and the package version in the manifest is 0.0.0, which for a private package is the convention of not versioning the app itself.
The maintainer is explicit about the project's origin and about the intent. The project was inspired by an earlier double-pinyin practice tool, and the author credits it with being how they learned the layout themselves. And the request at the end is worth quoting in substance: if the project has helped you, spend the time you saved enjoying life and being kind to yourself.
That is a small thing, but it tells you what kind of project this is. It is a tool built by somebody who solved their own problem and is sharing it, and the achievement system exists to make a solo practice app bearable.
The four practice modes, and why they are ordered that way
The main features list four practice modes, and the screenshots section shows three of them plus the settings screen, which is a good way of understanding the progression.
There is the random mode, where syllables come up in no particular order. There is the initial mode, which drills the initial consonants specifically, and the final mode, which does the same for the vowel parts. And there is the long-sentence mode, which is what the screenshots call the p-mode, where whole sentences are typed rather than isolated syllables.
The structure is a difficulty ladder, and the reasoning behind it is straightforward. Random syllables are the most like real typing, because in real use you type whatever word you are thinking of. But random is also the worst way to learn, because the mapping is learned by seeing the same association repeatedly, and random ordering gives you that repetition without giving you the structure.
The consonant and vowel modes are the middle. Each isolates one half of the double-pinyin mapping, so the exercise is a lookup for one component rather than two. Once the halves are familiar, the long-sentence mode puts them back together in context, which is where the skill actually has to work, and where the typing speed of a real session is measured rather than the recall of a chart.
There is also support for custom input articles, so a learner can practise with text they care about rather than a fixed corpus, which is the same idea as the custom layouts and follows the same pattern of letting the user supply the text.
And there is the progress statistics, described as being clear at a glance, plus an achievement system marked as work in progress. Those two features together are the answer to the problem every drill app has, which is that a chart of statistics and a row of badges are what make a repetitive exercise worth returning to.
The layout configuration, and why one-to-many mappings are refused
The contributing documentation answers the most useful question first: how do I add a new double-pinyin layout? You edit one file, src/utils/spconfig.json, following the format of the existing entries, and open a pull request explaining where the layout comes from.
The file format is a map from layout name to two maps. The keyMap assigns a keyboard key to a syllable, and the comment gives the order as key, then final, then initial, so an entry such as q mapping to a list of iu and u readings and then to the initial q. When a final has more than one reading, the alternatives are separated by an English comma. The zeroMap is the second map and handles the zero-initial case, where a syllable has no initial consonant and needs a dedicated key, with the same key-then-pinyin ordering.
So the data model is small and readable, and the contribution path is a single JSON file. That is a well-chosen contribution surface, because adding a layout is a data change rather than a code change, and a pull request adding one layout is exactly the kind of atomic, easily reviewed change the contributing guide asks for.
The FAQ then gets to the part that actually explains how the tool works, and it is the most interesting passage in the README. If certain pinyin cannot be recognised in a custom layout, check whether the layout has a one-to-many double-pinyin mapping, where a single double-pinyin input maps to several possible pinyin. That raises the collision rate of the input, and the tool deliberately does not support such layouts.
That is a real design decision rather than a limitation nobody has got to. In a double-pinyin layout, the two keys of a syllable are chosen from the consonant and vowel halves, and a well-formed layout guarantees that a pair of keys identifies exactly one syllable. Allow one pair to mean several syllables and the layout stops being decodable without context, and the collision rate goes up, so the input becomes ambiguous. The tool refuses those layouts rather than trying to guess.
The second FAQ explains the other limitation, and it is a good one. When the list of possible pronunciations for a character is too long, it is truncated for display. The README is careful to say that although the list is not fully shown, the judgement still works correctly. So the display is lossy and the checking is not, which is the right way round: the learner sees a shortened candidate list and is still graded against the full one.
And for a learner who just wants their own layout rather than a contribution, there is a local route. The settings screen has an add custom layout option under the current mode, so personal layouts do not need a pull request.
The stack, and what it says about the shape of the app
The package manifest describes a straightforward Vue application and the choices are all modern, which suggests the code is current.
The runtime dependencies are few. Vue at 3.2.25 and vue-router at 4 are the framework and the router. Pinia at 2.0.14 is the state store, and pinia-plugin-persistedstate at 1.6.1 is the plugin that persists that state to local storage, which is exactly what a practice app needs, since your progress and your settings have to survive a page reload. Less at 4.1.3 is the stylesheet preprocessor.
The build is standard Vite, and the scripts section of the manifest is where you can see it:
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview",
"lint": "eslint --ext .ts,.vue src",
"fix": "yarn lint --fix",
"prepare": "husky install",
"test": "vitest"
},So the dev script runs vite, the build script runs vue-tsc --noEmit and then vite build, so the type check gates the production build, and the preview script serves the built output. The lint script runs eslint over src with the .ts and .vue extensions, and the fix script runs the same with --fix. The prepare script installs husky, and there is a .husky/ directory in the tree along with an .eslintrc.js, a .vscode/ directory, an .editorconfig and a .prettierrc.
One dependency is worth singling out. @napi-rs/pinyin at 1.7.0 is in the dev dependencies rather than the runtime ones, and it is a native Node binding for pinyin conversion. That is what the tool uses to turn Chinese characters into their pinyin, which is the step that makes the exercise possible in the first place: given a character, produce the syllables it can be typed as, so the exercise can show the character and check what you typed.
The test setup is vitest with jsdom at 20.0.1 for the DOM environment, and ts-node at 10.8.1 for running TypeScript directly. The typescript version is 4.5.4, which is on the older side, and the eslint stack pairs @typescript-eslint with @vue/eslint-config-typescript and eslint-plugin-vue, with @rushstack/eslint-patch for the formatter patch that makes the TypeScript rules work with the Vue parser.
The build tooling is a Yarn project, since there is a yarn.lock alongside the package-lock.json, and the scripts use yarn in the fix command, so the two lockfiles are a leftover rather than a deliberate choice.
And the repository has a scripts/ directory and a screenshots/ directory, the latter holding the images the README embeds.
How to evaluate it, and what to check first
There are four things to consider.
First, whether it fits your target layout. The preset layouts cover the common schemes, and the custom layout path is documented, so the question is whether the particular scheme you use is among the presets. If it is, the tool is immediately usable. If not, adding it is a JSON file and a pull request, which is a low bar but still a bar.
Second, what the tool does not do. It is a practice tool. It has no IME, it does not run on Windows or macOS as an input method, and it does not integrate with your system keyboard. Its value is entirely in the drilling and the statistics, and the long-sentence mode is the closest it comes to realistic typing. If your goal is to type Chinese quickly in your day job, this is a training aid for the mapping rather than an input method.
Third, the achievement system is marked work in progress, and the features list marks it the same way. So the retention mechanism that would make a drill app worth returning to is the part that is most apt to change. The progress statistics are the more finished half.
Fourth, the licensing, and it is unusual. The project is MIT licensed and also uses the Anti 996 License as a supplementary open-source licence, with both files in the tree, LICENSE and LICENSE.anti-996. The supplementary term restricts use by employers requiring staff to work long hours. If you are an individual or an organisation with conventional working hours this is a non-issue, but it is a condition on use, so it is worth reading rather than assuming, since a second licence file alongside MIT is not something you see every day.
What you get is a focused, small, well-scoped tool for one specific skill, built by one person, with the configuration exposed as data so that the community can extend it, and with the awkward edge cases, the truncated pronunciation lists and the refused one-to-many layouts, documented honestly in the FAQ. That combination of a narrow, well-understood purpose and an unusually candid FAQ is what makes it worth an hour of your afternoon.
Editorial conclusion
Adopt Shuangpin if you are learning a Chinese double-pinyin layout and want something more structured than reading a chart, since the four modes drill the mapping in a sensible order and the progress statistics and achievements give a reason to come back. Do not expect an input method, because it is a browser practice tool with no system integration, and do not treat the achievement system as a finished feature since the README marks it as work in progress. Before you commit, check whether your target layout is among the presets, read both licence files, since the MIT terms are supplemented by the Anti 996 License, and if you need a layout that is not there, remember that the contribution path is one JSON file and a pull request explaining the source of the scheme.
Frequently asked questions
What is the Shuangpin practice tool?
It is a Vue web application for learning to type Chinese with a double-pinyin input method, where each key carries two syllables and the layout must be memorised as a mapping. It is MIT licensed with the Anti 996 License as a supplementary term, and the live site is at shuangpin.simplenaive.cn.
What practice modes does the Shuangpin tool have?
Four: random mode, initial mode, final mode and long-sentence mode. The random mode presents syllables in no order, the initial and final modes drill one half of the double-pinyin mapping at a time, and the long-sentence mode types whole passages so the halves are combined in context.
How do I add a new double-pinyin layout to the Shuangpin project?
Edit src/utils/spconfig.json following the format of the existing entries, which maps a layout name to a keyMap of keyboard key, final and initial, and a zeroMap for syllables with no initial consonant. Then open a pull request explaining where the layout comes from. For personal use only, a local custom layout can be added from the settings screen under the current mode instead.
Why does the Shuangpin tool reject some custom layouts?
Because they contain a one-to-many double-pinyin mapping, where a single key pair corresponds to several possible pinyin. That raises the collision rate of the input and makes the layout ambiguous, so such layouts are not supported. The FAQ also notes that where a character's list of pronunciations is too long the display is truncated, but the checking still works against the full list.
What is the Shuangpin project built with?
Vue 3 with vue-router 4, Pinia with the persisted-state plugin, Less for styles, and Vite for the build, with vue-tsc type checking gating the production build. The dev dependencies include @napi-rs/pinyin for converting characters to pinyin, vitest with jsdom for tests, and eslint with the Vue and TypeScript configurations. The package is built as a private project with a 0.0.0 version.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/yidadaa-shuangpin)Was this useful?