Architecture for contributors
Two crates
crates/abax-core/ pure logic: no UI, no I/O, no randomness of its own
soroban.rs rods and the soroban: beads <-> digits <-> numbers
moves.rs the bead-move engine: the exact move list for adding or
subtracting a digit (complements, carry, borrow, finger order)
arith.rs multi-digit add/sub; multiplication and division as
narrated step sequences (Kojima's standard methods)
curriculum.rs the 15 skills, prerequisites, ladders, lesson text and demos
generator.rs drill items per skill and ladder step
scheduler.rs BKT, EWMAs, Elo, ladder rules, mastery, review, session plan
stats.rs history, momentum, chart series, session log
store.rs the versioned save document and its migration
crates/abax/ the eframe app: a binary on the desktop, a cdylib on Android
lib.rs App: screens, settings, autosave, capture and bench modes,
android_main
main.rs desktop entry point (window size, bench options)
soroban_view.rs the interactive soroban: hit testing, tap and drag,
spring animation, hints, building render instances
render/ the wgpu paint callback (mod.rs) and its shader (soroban.wgsl)
screens/ home, practice, lesson, drill, flash, picker, stats, settings
keypad.rs on-screen keypad and keyboard mapping
theme.rs, ui.rs palette, finishes, fonts; shared widgets
charts.rs the stats charts
audio.rs the synthesised click (desktop, cpal)
storage.rs data directory, atomic save, load with backup
android/ manifest, resources, build-apk.sh
packaging/ .desktop file, icon, install.sh, Info.plist, make-app.sh
docs/ this manual, the landing page, the screenshots
research/ sources and the bead-move fixture tables
verify the release gate
abax-core holds the rules and most of the tests. Randomness comes from
the caller: generators take a dice closure, the scheduler a seeded
xorshift generator.
Data flow
- Input. A tap, drag or key goes to
SorobanView, which updates itsSorobanmodel and animates the beads towards it. - Checking. The active screen compares the model with the current
Item(fromgenerator::generate). Chain items follow the running total operand by operand; typed items compare the keypad buffer. - Recording.
DrillState::submitcallsScheduler::record(skill, correct, seconds, now), which updates that skill’s state and returns whether it stepped up, stepped down or became mastered, and appends anAttempttoHistory. - Saving. The app marks itself dirty; within 5 seconds, and on exit,
storage::savewrites the wholeSaveFileatomically. - Planning. The home screen asks
Scheduler::next_skill_to_learnfor an untried lesson, otherwiseScheduler::plan_sessionfor warm-up, focus and cool-down drills.
Adding a skill
curriculum.rs: add aSkillIdvariant in teaching order and toSkillId::ALL; give it acode,name,short_name,prerequisites,base_difficulty,benchmark_secondsand aladder; add itsLessontoLESSONS.generator.rs: generate its items ingenerate, and if it is a bead skill, give it aConstraintinconstraint_forsaying which rules it allows and which it must contain.- The app:
drill_kind_forinscreens/drill.rs, the groups inscreens/picker.rs, and the session start inApp::start_pending_orif it needs a special mode. - Tests already guard the shape: prerequisites must form a graph in teaching order with one root, and every skill needs a lesson and a ladder of at least three steps that starts untimed.
Old save files keep loading: Scheduler::fill_missing gives a new skill a
fresh state. Do not rename existing variants: their names are the keys in
the save file.
Adding a drill type
generator.rs: anItemvariant, withanswer,prompt,operand_countandsolution_steps(the moves a wrong-answer replay shows).stats.rs: aDrillKindvariant, if the stats should tell it apart. Append it; variant names are stored.screens/drill.rs: how the item is set up on the soroban (setup_item), whether the answer is typed or worked on the beads (typed_answer), how many rods it needs (rods_needed) and what the replay shows (replay_steps_for).
Tests
The tests include:
- the complete 10 × 9 addition and 10 × 9 subtraction tables from the research notes: for every digit on the rod and every digit added or subtracted, the exact move list, rule and order;
- worked multiplication and division examples from Kojima, including division with revised quotient digits;
- generators: every item for a skill uses that skill’s rule and nothing beyond it;
- the scheduler: the BKT sequence, the EWMA sequences, U(n), Elo monotonicity, the mastery gate rejecting four lucky answers and slow answers, forgetting and the session planner choosing only skills on the suggested path or already met, adding a light review when a prerequisite is weak, and never failing on any mix of known, practised and skipped skills; “I know this” seeding 0.80 (not 1.0) and the per-skill reset;
- save files: round trip, unknown fields ignored, missing fields defaulted, bad input an error rather than a crash; atomic write and backup on a damaged file.
Run them with cargo test --workspace, or the whole gate with ./verify.
Bead-move changes must keep the full tables green.
Conventions
- Clippy warnings are errors;
cargo fmtdecides formatting. - Western digits (0 to 9) in every string.
- Palette, motion and interaction:
docs/internals.md. - Captures live only in
docs/screenshots/.
See CONTRIBUTING.md
for how to propose a change.