4.8 KiB
4.8 KiB
Design Notes
Soroban Representation
Number Encoding
The soroban uses a bi-quinary system where each column represents a decimal digit:
- Heaven bead: 1 bead worth 5 when active
- Earth beads: 4 beads worth 1 each when active
For any digit 0-9:
- Heaven bead is active if digit ≥ 5
- Number of active earth beads = digit mod 5
Visual Conventions
-
Active beads: Solid black, positioned against the reckoning bar
- Heaven beads move down when active
- Earth beads move up when active
-
Inactive beads: Light gray, positioned away from the bar
- Heaven beads rest at top when inactive
- Earth beads rest at bottom when inactive
-
Column ordering: Right-to-left place values (ones, tens, hundreds)
- Matches traditional soroban layout
- Rightmost column is always ones place
Rendering Algorithm
for each digit in number:
heaven_active = 1 if digit >= 5 else 0
earth_active = digit % 5
draw_rod()
draw_heaven_bead(active=heaven_active)
for i in range(4):
draw_earth_bead(active=(i < earth_active))
draw_reckoning_bar()
Duplex Printing Alignment
Challenge
Double-sided printing must align front and back cards precisely when using long-edge binding (standard for portrait orientation).
Solution
- Page mirroring: Back side cards are arranged in reverse column order
- Grid consistency: Same grid dimensions on both sides
- Registration marks: Optional alignment dots in trim area
- Safe margins: 5mm default buffer inside each card
Implementation
// Front side: normal left-to-right layout
grid(columns: 2, rows: 3,
card1, card2,
card3, card4,
card5, card6)
// Back side: columns reversed for long-edge flip
grid(columns: 2, rows: 3,
card2_back, card1_back, // Note reversed
card4_back, card3_back,
card6_back, card5_back)
Vector Graphics Strategy
Why Typst?
- Native vector support: Built-in drawing primitives
- Font embedding: Automatic TTF/OTF embedding
- Lightweight: ~30MB install vs. 3GB+ for TeX
- Deterministic: Same input → same output
Drawing Primitives Used
circle(): Beads (with fill and stroke)rect(): Rods and reckoning barplace(): Absolute positioning within cardbox(): Layout containers with margins
No Rasterization
All elements remain vectors through the entire pipeline:
- Typst → PDF (vector primitives)
- qpdf linearization (preserves vectors)
- No image assets or bitmaps
Configuration System
Hierarchy
- Built-in defaults: Hardcoded in Python
- Config file: YAML/JSON overrides
- CLI arguments: Highest priority
Merge strategy
final_config = defaults
final_config.update(file_config)
final_config.update(cli_args)
Build Determinism
Sources of Non-determinism
- Random shuffling: Controlled via
--seed - File timestamps: Not embedded in PDF
- Font subsetting: Consistent with bundled fonts
Ensuring Reproducibility
- Fixed random seed produces identical shuffle
- Bundled fonts prevent system font variations
- Typst's deterministic rendering
- No external network calls or timestamps
Performance Considerations
Optimizations
- Single-pass rendering: Generate all cards in one Typst run
- Batched operations: Group all cards per page
- Minimal dependencies: No heavy frameworks
- Direct PDF generation: No intermediate formats
Scalability
Tested ranges:
- 0-9: ~0.5 seconds
- 0-99: ~1 second
- 0-999: ~3 seconds
- 0-9999: ~15 seconds
Memory usage remains constant regardless of range size.
Font Selection
DejaVu Sans Choice
- Open source: Free license, redistributable
- Complete coverage: Full ASCII + extended Latin
- Clear numerals: Distinct digit shapes
- Cross-platform: Renders identically everywhere
Embedding Strategy
- Fonts copied to
fonts/directory - Typst uses
--font-pathflag - Full embedding (not subsetting) for consistency
Future Enhancements
Potential improvements while maintaining core simplicity:
- Additional layouts: 12-up, 16-up for smaller cards
- Color coding: Optional colored beads by place value
- Mixed practice: Combine different number ranges
- Answer variations: Show decomposition (e.g., "20 + 3")
- Export formats: SVG individual cards, PNG previews
Testing Methodology
Validation Steps
- PDF integrity:
qpdf --checkvalidates structure - Vector verification: No embedded images
- Font embedding: All fonts included
- Print testing: Physical duplex print alignment
- Cross-platform: Tested on multiple macOS versions
Edge Cases Handled
- Empty number list → Error message
- Invalid range → Clear error
- Missing dependencies → Helpful install instructions
- Printer margin variations → Configurable margins