pax_global_header 0000666 0000000 0000000 00000000064 15227314342 0014515 g ustar 00root root 0000000 0000000 52 comment=59e16ae27ae69664f54579f6c111b625b046d187
kanarenshu-0.1.4/ 0000775 0000000 0000000 00000000000 15227314342 0013656 5 ustar 00root root 0000000 0000000 kanarenshu-0.1.4/.github/ 0000775 0000000 0000000 00000000000 15227314342 0015216 5 ustar 00root root 0000000 0000000 kanarenshu-0.1.4/.github/FUNDING.yml 0000664 0000000 0000000 00000001571 15227314342 0017037 0 ustar 00root root 0000000 0000000 # These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: nuixyz
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
thanks_dev: # Replace with a single thanks.dev username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
kanarenshu-0.1.4/.github/workflows/ 0000775 0000000 0000000 00000000000 15227314342 0017253 5 ustar 00root root 0000000 0000000 kanarenshu-0.1.4/.github/workflows/release.yml 0000664 0000000 0000000 00000004632 15227314342 0021423 0 ustar 00root root 0000000 0000000 name: release
on:
push:
tags:
- "v*"
permissions:
contents: write
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version: "1.23"
- uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AUR_KEY: ${{ secrets.AUR_KEY }}
update-source-pkgbuild:
needs: goreleaser
runs-on: ubuntu-latest
steps:
- name: Set up SSH for AUR
run: |
mkdir -p ~/.ssh
echo "${{ secrets.AUR_KEY }}" > ~/.ssh/aur
chmod 600 ~/.ssh/aur
ssh-keyscan aur.archlinux.org >> ~/.ssh/known_hosts
- name: Clone kanarenshu AUR repo
run: |
GIT_SSH_COMMAND="ssh -i ~/.ssh/aur -o IdentitiesOnly=yes" \
git clone ssh://aur@aur.archlinux.org/kanarenshu.git aur-kanarenshu
- name: Bump pkgver and sha256sum
run: |
cd aur-kanarenshu
VERSION="${GITHUB_REF_NAME#v}"
URL="https://github.com/nuixyz/kanarenshu/archive/refs/tags/${GITHUB_REF_NAME}.tar.gz"
SHA=$(curl -sL "$URL" | sha256sum | cut -d' ' -f1)
if [ -z "$SHA" ]; then
echo "Failed to compute sha256sum. Aborting."
exit 1
fi
sed -i "s/^pkgver=.*/pkgver=${VERSION}/" PKGBUILD
sed -i "s/^pkgrel=.*/pkgrel=1/" PKGBUILD
sed -i "s/^sha256sums=.*/sha256sums=('${SHA}')/" PKGBUILD
echo "Updated PKGBUILD:"
cat PKGBUILD
- name: Regenerate .SRCINFO
run: |
cd aur-kanarenshu
docker run --rm -v "$PWD:/pkg" -w /pkg \
--user "$(id -u):$(id -g)" \
archlinux:base-devel \
bash -c "makepkg --printsrcinfo > .SRCINFO"
- name: Commit and push
run: |
cd aur-kanarenshu
git config user.name "nuixyz"
git config user.email "contactme@nuixyz.dev"
if git diff --quiet PKGBUILD .SRCINFO; then
echo "No changes to commit — skipping"
exit 0
fi
git add PKGBUILD .SRCINFO
git commit -m "kanarenshu: update to ${GITHUB_REF_NAME}"
GIT_SSH_COMMAND="ssh -i ~/.ssh/aur -o IdentitiesOnly=yes" git push
kanarenshu-0.1.4/.gitignore 0000664 0000000 0000000 00000000141 15227314342 0015642 0 ustar 00root root 0000000 0000000 # build output
kanarenshu
*.log
debug.log
/dist/
# test files
*_test.go
*.exe
*.out
demo.tape kanarenshu-0.1.4/.goreleaser.yaml 0000664 0000000 0000000 00000003503 15227314342 0016751 0 ustar 00root root 0000000 0000000 version: 2
before:
hooks:
- go mod tidy
builds:
- main: ./cmd/kanarenshu
env:
- CGO_ENABLED=0
ldflags:
- -s -w -X main.version={{.Version}}
goos:
- linux
- windows
- darwin
goarch:
- arm64
- amd64
archives:
- formats: [tar.gz]
name_template: >-
{{ .ProjectName }}_
{{- title .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else }}{{ .Arch }}{{ end }}
format_overrides:
- goos: windows
formats: [zip]
checksum:
name_template: "checksums.txt"
changelog:
sort: asc
use: git
abbrev: 7
groups:
- title: "✨ Features"
regexp: '^feat(\(.+\))?:'
order: 0
- title: "🐛 Bug Fixes"
regexp: '^fix(\(.+\))?:'
order: 1
- title: "🧹 Chores & Refactors"
regexp: '^(chore|refactor|perf)(\(.+\))?:'
order: 2
- title: "Other"
regexp: ".*"
order: 999
format: "* {{ .Message }}"
filters:
exclude:
- "^docs:"
- "^test:"
- "^Merge pull request"
- "^Merge branch"
aurs:
- name: kanarenshu-bin
homepage: "https://github.com/nuixyz/kanarenshu"
description: "A minimal TUI application to practise Japanese from the terminal."
maintainers:
- "nuixyz"
license: "MIT"
private_key: "{{ .Env.AUR_KEY }}"
git_url: "ssh://aur@aur.archlinux.org/kanarenshu-bin.git"
provides:
- kanarenshu
conflicts:
- kanarenshu
package: |-
install -Dm755 "./kanarenshu" "${pkgdir}/usr/bin/kanarenshu"
install -Dm644 "./README.md" "${pkgdir}/usr/share/doc/kanarenshu/README.md"
install -Dm644 "./LICENSE" "${pkgdir}/usr/share/licenses/kanarenshu/LICENSE"
commit_author:
name: nuixyz
email: contactme@nuixyz.dev
commit_msg_template: "kananrenshu-bin: updated to {{ .Tag }}"
goamd64: v1
kanarenshu-0.1.4/LICENSE 0000664 0000000 0000000 00000002047 15227314342 0014666 0 ustar 00root root 0000000 0000000 MIT License
Copyright (c) 2026 nuixyz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
kanarenshu-0.1.4/README.md 0000664 0000000 0000000 00000013223 15227314342 0015136 0 ustar 00root root 0000000 0000000
かな練習 · kanarenshu
A minimal TUI application to practise Japanese kana and kanji from your terminal
---
## Features
- **Hiragana, Katakana, and Mixed** modes for kana practise.
- **Kanji mode**: Graded by JLPT level (the app supports only N5 level currently), testing on on'yomi, kun'yomi, and English meaning.
- **Weight-based character selection** - Characters you answer wrong appear more often, while mastered ones fade out.
- **Level-based progression system** - Unlock new characters as you level up.
- **Per-character stats**: Tracked separately for each mode, including each kanji tier.
- **5 built-in themes**: Tokyo Night, Catppuccin, Gruvbox, Nord, Dracula. Cycle through each theme using `ctrl + t` or get a live preview from the settings menu.
- **Configurable** - lives, hints, and theme, editable via config file or the in-app settings menu.
---
## Installation
Pre-compiled binaries are available in the [Releases](https://github.com/nuixyz/kanarenshu/releases) section.
### AUR
Using Yay:
```bash
yay -S kanarenshu
```
Using Paru:
```bash
paru -S kanarenshu
```
### Nix
Nix users can directly use this repository to get the latest kanarenshu for their system.
Add in your `flake.nix`:
```nix
inputs.kanarenshu.url = "github:nuixyz/kanarenshu";
```
Pass inputs to your modules and then in `configuration.nix`:
```nix
environment.systemPackages = [
inputs.kanarenshu.packages.${pkgs.stdenv.hostPlatform.system}.default
];
```
### Homebrew
Coming soon
### From Source
```bash
git clone https://github.com/nuixyz/kanarenshu
cd kanarenshu
go build ./cmd/kanarenshu
```
### Requirements
- Go 1.21 or later (uses `//go:embed`)
---
## Usage
```
kanarenshu
```
Use the arrow keys or `j/k` to navigate the menu,
`enter` to select.
### Keyboard shortcuts
| Key | Action |
|-----|--------|
| `enter` | Submit answer |
| `esc` | Return to menu |
| `ctrl+t` | Cycle through themes |
| `ctrl+c` | Quit |
| `q` | Quit (menu) |
| `s` | Open settings (menu) |
### Romaji input
Both strict Hepburn and common alternatives are accepted by default:
| Kana | Accepted |
|------|----------|
| し | `shi`, `si` |
| ち | `chi`, `ti` |
| つ | `tsu`, `tu` |
| ふ | `fu`, `hu` |
| じ | `ji`, `zi` |
| ん | `n`, `nn` |
### Kanji mode
Select **Kanji** from the main menu, then choose a JLPT level. For each character, any of its on'yomi readings, kun'yomi readings or the English meanings are accepted as a correct answer. A wrong answer reveals the readings and meanings as a hint. Progress of each JLPT tier is tracked independently.
---
## Progression
Kana are grouped into levels of 5, kanji are grouped into levels of 10. The app uses an adaptive learning algorithm to determine how often a character appears in a group:
- A correct answer halves a character's weight.
- A wrong answer doubles it (capped at the initial weight of 400).
- A character is considered mastered once it reaches a threshold weight of 25 or below.
- A level up condition is triggered once every character in the current group is mastered.
The highest unlocked level for each mode is saved automatically and resumed on next launch.
---
## Configuration
On first run, kananrenshu creates a config file at:
```
~/.config/kanarenshu/config.toml
```
```toml
theme = "tokyo-night" # tokyo-night | catppuccin | gruvbox | nord | dracula
lives = 3 # 0 = infinite
romaji_strict = false # true = Hepburn only (e.g. "shi", not "si")
show_hints = true # show reading hint after a wrong answer
```
Changes take effect on next launch, or can be applied live via the in-app settings menu
---
## Themes
Themes can be changed in the settings menu (`s` from the main menu) or cycled in-session with `ctrl+t`. The selected theme is saved to config automatically on save.
| Name | |
|------|-|
| `tokyo-night` | Dark blue — default |
| `catppuccin` | Catppuccin Mocha |
| `gruvbox` | Gruvbox Dark |
| `nord` | Nord |
| `dracula` | Dracula |
---
## Data files
| Path | Contents |
|------|----------|
| `~/.config/kanarenshu/config.toml` | User configuration |
| `~/.local/share/kanarenshu/progress.json` | Level progress and per-character statistics |
| `~/.local/share/kanarenshu/debug.log` | Debug log |
XDG environment variables (`$XDG_CONFIG_HOME`, `$XDG_DATA_HOME`) are respected if set.
---
## Project layout
```
cmd/kanarenshu/ entry point
internal/data/ hiragana, katakana, and kanji groupings; per level pools
internal/game/ session logic, scoring, weight-based progression
internal/storage/ config and progress persistence
internal/theme/ embedded TOML theme palettes
internal/ui/ Bubble Tea screens and reusable components
pkg/romaji/ kana <-> romaji tables and answer checking
pkg/kanji/ kanji data and answer validation (readings/meanings)
```
---
## Dependencies
- [Bubble Tea](https://github.com/charmbracelet/bubbletea) — TUI framework
- [Bubbles](https://github.com/charmbracelet/bubbles) — UI components
- [Lip Gloss](https://github.com/charmbracelet/lipgloss) — Styles and layout
- [BurntSushi/toml](https://github.com/BurntSushi/toml) — TOML parsing
---
## License
MIT
kanarenshu-0.1.4/assets/ 0000775 0000000 0000000 00000000000 15227314342 0015160 5 ustar 00root root 0000000 0000000 kanarenshu-0.1.4/assets/hiragana_session.png 0000664 0000000 0000000 00001300130 15227314342 0021201 0 ustar 00root root 0000000 0000000 PNG
IHDR 0gV IDATxy-u| n @}ߵZ,D263yb옞qt y^"nInki-Yiy$n/
E\}=ɪw2O@ܥ=[fGs#~^r9>;`9E>aH?9 [ƢpF4zSՕ57!< ߮h)^W/잻#<0
ND߭p652*sp,R 3B[Ssb6/#~sy# 3j5 P)yto_w6tZxBgqr(QT2{kMBBhaEkngKl[磨U.P~%em:4˫!
85Ex7TtGsVV
F2#g
Z-%&g{ro4
mgv˂m9)
t#oB^gvH潙?{ٞ\42:qZua85Q}(3%ѩ!lc̒R~ڷ[cG@Kv`I}5զT½U!IӺk2&f~tJ~Ssjn+[}R};C#^N-4p Y&oMJ?ceoг6YY{IS&tںe{`G8{8l-o[y&P9X:xKzv'LrJ2d{t':Ξ\6;哵=Lcrƍ#Z{:TQW67R_<e\xƳMgOɟg~3W^u}=&xdG U3
Y2o*h, ^?EfruYa+_gͿΖhOO'+XNHqP4JZ!ٞx/^\uhp#(kNmJ>i8/(R0ܰpSvo8iq0TQ|nM8!IP#|1Moe+[Gx}J\ !o/C%] lBK-7i9X#isa>jߙ>Sx;oGAYr2teJp\00Qe$o!-)%e0
%36Ԑ<&N=}TJhI5X72l2Q~hh3#[A9DȤJbcyEΨv4BB~ảqS =Vhp%9nPvLZgIq;JؘECY]?<9ϕ>+`X/h94n gg`;H(YLoئg=]vf:-t4<t ()ZJp's"--TvԘG@)Өz+4H SJ;^%{3t A6ݙtrñ5%
:{]ENxQ:Ipp# dO﨟7]DN#&1uzDz{qSU"Jp |?*48I;/|v}"X'ki⸙pT=n "~6=
ol/Ji[ʠr,#f{gw|vŕ}w
tQ;5e-ahS>{
_6avͻ6eN?=`3lm,K/~'&vO0qӜ T2>j<ģx{tz \鉭t0o%OS#*X̒DQj,gX>_^mNcP}D ĕóJp'%|Nt`{U*1zA`܇cݣ@Q_% s#\P(Fmø26[7}6ٮ:h&>+O<1>}n}(
%I:IC|}pp:a$P2!:0P^hhiW4&5Oژz$[Iapj
S}}9>#\|l
aT>VᩤJfϬUx1Bpkh߯Bw#0GcciϚf{W_so.qU;=">68sWd"p_7?rJ4@ƿ xͶQC>5%kr_{'G2dKm|9oᴒux,3zR%Λ1Ƨ %
ݗ.i'e4J)SP6G8¥ 7I8j?m:pR"m]Nd& Kˎ~'Eۯ~Eր-)}.gy
8b%n,11ҳ)6$A5$Zɪ(kz?tm55UiXRCSymjFIl#Ψ/MA# p O젧
=59)LA}eTv#*P/R#Tq%'V1*'8${I#U8I94B`Bm'> <*3{2[6T|NWHmW
sgS oN/ 5)pl
2hfQ2鄛Iͷ;v[ܳEjf:CM1iT8ӎPT(#(;FCҭ
a]&^)&"QE'͕vT\W'?fKu,$;>ģ8$ c#߾1a_v,1H-68TQ]kkVpSUץm:c1qڇC>J(c#y6fctM_Xg(gt9mk?3 F^-5❟F|ulM0)T.6eО,);AsByð>W$+Zj7POeD]p>UH$Z;uƙveV
T,T*p͓_͆8;r{:6Xe(ijӴ_0DtLuX_ZO 8J;AЅT;rnCR`k =}P{VXVEq#sE[ʘ^$IuzQ2_(Y25)_q_[֏Ó],Nq:<9?om6FוvfLnm4L)VIp*$p퀾l,?%SGm&l49dYr(G9f{qPuMAUhbaǯ~=e>2N֟l|
dn3d~c#rQVA,l|?ml(Ut>>ʜI%J^ihGK4>Fj.BFp.G<ȋ?Ei8 wi:(bG-@娴
8dhO<ՂmZy'-Lx?8zoܟqpF8'΅C4&EkN%q|-~{(_z.r탑ɠZwjR{G}xC3E^_i:Q/iZIh 3TdV4UX%n戞J`/*ly'9Tx.p,Gxܗm63/S dpݸߍ2axƸa1nju%xFG9s\Wq
EUG-1ꝧBb s3>؎YY7tKhl$(6ᚵC6l# SzP;ϙFT+ִ)M,oG!o]c#`BJ%F^[m;[銺г9CPõGQğߵ_UӀbNKډ!z#RpQ v{27(%7O%7Trs2'/kǴ3dR`FUa^Gt1Ah#C[D[_*
KܼNO͘s7S/-_uB
$LNغS2#Q֤jKJ*U9RxOx@)"ܶk[p >3.n
tq|w}Ʋ6ڤ[eJ[)=}qf~b?.أēEst6Jc?KṰxI%zq<~܈>N#djJ
9m11i7&?qvͬ l+RJL- im5Ϩ#\.^ԫ>kʷh~=L6u#\{CH2biQ79趫~r|Npz]Ǻoid}#<9ʇ++th"A
ydiv/9xOVx_Q+s?<01S0ef2x9F&[n(˪h0Vl$As>{AF%rTDg@6O㟴Os,%J-Z%k|yu pxΔsn&i͒B\ȍ+@L8^kj;מWq0ɚwM~g8QXǹt1жd,]¢~|5k qSwmjq_ccrm/W2(mfXYCe> vhG0B}Qas
U\zcP-<~ ܪ O!,
Y4"窄q6S|6Zf|"G%`S%oFRH>/UPs{>|Q99~/hǪ%,_9Ӎz 2miKø]W]>9FHApQ)km[Ӂf2lJZ^fHZ;
k85yf;ttveЇbZ*:eCl{Ɏ匶~Htv<#mOs~F`]qvX?nPO6lxnc0imY#/`,ExlC̴_6[!:XEªy$DgS}z9GZ_~S$JDaFpJ9U#~Y4yD|Kzl_
" \cP~O.mBPH30[&jTP*˚ވݥJ#Detڵ!&6KP+[S^6*9g]CStmn;S+rvZ8Ak"jc9ll
Om.*0K[/?G1O#]\dg9G'Ba#֩{2*Ѩ+]D|pa
eO7@gM[ܥ5/pVpj@6
nUn\6X32o|k4~
ẇ{]ϙ5@[m VUq>D8L7;obg9]Gǡ@1XP
G9ف,H_^;p }u[d_x.D0>0Sm_~bxu8EΛdL@X32`%1V k#(樈6ՆO쓹$*(QϠRke0J;䱃IBkjAS?sGcTQ5lm]h]Pp`:6g
O}0N/jYb9IO%2A%īiMkP+QEu=j2.i_GxVofzk߿,+('fG9Icݥ&