Add comprehensive documentation
- README.md: Main documentation with quick start, usage, and examples - DESIGN.md: Technical implementation details and architecture decisions - INSTALL.md: Detailed installation guide for macOS Documentation covers soroban representation, duplex printing, vector graphics strategy, and configuration options. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
75e9337e4e
commit
8b38ca6521
|
|
@ -0,0 +1,185 @@
|
|||
# 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
|
||||
|
||||
1. **Active beads**: Solid black, positioned against the reckoning bar
|
||||
- Heaven beads move down when active
|
||||
- Earth beads move up when active
|
||||
|
||||
2. **Inactive beads**: Light gray, positioned away from the bar
|
||||
- Heaven beads rest at top when inactive
|
||||
- Earth beads rest at bottom when inactive
|
||||
|
||||
3. **Column ordering**: Right-to-left place values (ones, tens, hundreds)
|
||||
- Matches traditional soroban layout
|
||||
- Rightmost column is always ones place
|
||||
|
||||
### Rendering Algorithm
|
||||
|
||||
```python
|
||||
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
|
||||
|
||||
1. **Page mirroring**: Back side cards are arranged in reverse column order
|
||||
2. **Grid consistency**: Same grid dimensions on both sides
|
||||
3. **Registration marks**: Optional alignment dots in trim area
|
||||
4. **Safe margins**: 5mm default buffer inside each card
|
||||
|
||||
### Implementation
|
||||
|
||||
```typst
|
||||
// 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?
|
||||
|
||||
1. **Native vector support**: Built-in drawing primitives
|
||||
2. **Font embedding**: Automatic TTF/OTF embedding
|
||||
3. **Lightweight**: ~30MB install vs. 3GB+ for TeX
|
||||
4. **Deterministic**: Same input → same output
|
||||
|
||||
### Drawing Primitives Used
|
||||
|
||||
- `circle()`: Beads (with fill and stroke)
|
||||
- `rect()`: Rods and reckoning bar
|
||||
- `place()`: Absolute positioning within card
|
||||
- `box()`: 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
|
||||
|
||||
1. **Built-in defaults**: Hardcoded in Python
|
||||
2. **Config file**: YAML/JSON overrides
|
||||
3. **CLI arguments**: Highest priority
|
||||
|
||||
### Merge strategy
|
||||
|
||||
```python
|
||||
final_config = defaults
|
||||
final_config.update(file_config)
|
||||
final_config.update(cli_args)
|
||||
```
|
||||
|
||||
## Build Determinism
|
||||
|
||||
### Sources of Non-determinism
|
||||
|
||||
1. **Random shuffling**: Controlled via `--seed`
|
||||
2. **File timestamps**: Not embedded in PDF
|
||||
3. **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
|
||||
|
||||
1. **Single-pass rendering**: Generate all cards in one Typst run
|
||||
2. **Batched operations**: Group all cards per page
|
||||
3. **Minimal dependencies**: No heavy frameworks
|
||||
4. **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
|
||||
|
||||
1. **Open source**: Free license, redistributable
|
||||
2. **Complete coverage**: Full ASCII + extended Latin
|
||||
3. **Clear numerals**: Distinct digit shapes
|
||||
4. **Cross-platform**: Renders identically everywhere
|
||||
|
||||
### Embedding Strategy
|
||||
|
||||
- Fonts copied to `fonts/` directory
|
||||
- Typst uses `--font-path` flag
|
||||
- Full embedding (not subsetting) for consistency
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Potential improvements while maintaining core simplicity:
|
||||
|
||||
1. **Additional layouts**: 12-up, 16-up for smaller cards
|
||||
2. **Color coding**: Optional colored beads by place value
|
||||
3. **Mixed practice**: Combine different number ranges
|
||||
4. **Answer variations**: Show decomposition (e.g., "20 + 3")
|
||||
5. **Export formats**: SVG individual cards, PNG previews
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
### Validation Steps
|
||||
|
||||
1. **PDF integrity**: `qpdf --check` validates structure
|
||||
2. **Vector verification**: No embedded images
|
||||
3. **Font embedding**: All fonts included
|
||||
4. **Print testing**: Physical duplex print alignment
|
||||
5. **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
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
# Installation Guide
|
||||
|
||||
## Quick Install (macOS)
|
||||
|
||||
```bash
|
||||
# Using the Makefile
|
||||
make install
|
||||
|
||||
# Then generate PDFs
|
||||
make
|
||||
```
|
||||
|
||||
## Manual Installation
|
||||
|
||||
### 1. Install Typst
|
||||
|
||||
Typst is the rendering engine that generates PDFs from templates.
|
||||
|
||||
#### Option A: Using Homebrew (Recommended)
|
||||
```bash
|
||||
brew install typst
|
||||
```
|
||||
|
||||
#### Option B: Direct Download
|
||||
1. Visit https://github.com/typst/typst/releases
|
||||
2. Download the latest macOS binary
|
||||
3. Extract and move to your PATH:
|
||||
```bash
|
||||
tar xzf typst-*.tar.gz
|
||||
sudo mv typst /usr/local/bin/
|
||||
```
|
||||
|
||||
#### Option C: Using Cargo (Rust)
|
||||
```bash
|
||||
cargo install typst-cli
|
||||
```
|
||||
|
||||
### 2. Install qpdf (Optional but Recommended)
|
||||
|
||||
qpdf is used for PDF linearization and validation.
|
||||
|
||||
```bash
|
||||
brew install qpdf
|
||||
```
|
||||
|
||||
### 3. Install Python Dependencies
|
||||
|
||||
```bash
|
||||
pip3 install -r requirements.txt
|
||||
# Or directly:
|
||||
pip3 install pyyaml
|
||||
```
|
||||
|
||||
## Verify Installation
|
||||
|
||||
```bash
|
||||
# Check all dependencies
|
||||
which typst && echo "✓ Typst installed"
|
||||
which qpdf && echo "✓ qpdf installed"
|
||||
python3 -c "import yaml" && echo "✓ PyYAML installed"
|
||||
|
||||
# Run a test build
|
||||
make test
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "command not found: brew"
|
||||
|
||||
Install Homebrew first:
|
||||
```bash
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
```
|
||||
|
||||
### "command not found: pip3"
|
||||
|
||||
Python 3 should be included with macOS. If not:
|
||||
```bash
|
||||
brew install python3
|
||||
```
|
||||
|
||||
### "Permission denied" errors
|
||||
|
||||
Use sudo for system-wide installation:
|
||||
```bash
|
||||
sudo pip3 install pyyaml
|
||||
```
|
||||
|
||||
Or use user installation:
|
||||
```bash
|
||||
pip3 install --user pyyaml
|
||||
```
|
||||
|
||||
### Typst font errors
|
||||
|
||||
The bundled fonts should work automatically. If you see font errors:
|
||||
1. Verify fonts exist: `ls fonts/*.ttf`
|
||||
2. Explicitly specify font path: `python3 src/generate.py --font-path fonts/`
|
||||
|
||||
## Dependencies Summary
|
||||
|
||||
| Component | Required | Purpose | Size |
|
||||
|-----------|----------|---------|------|
|
||||
| Python 3 | Yes | Script execution | Included with macOS |
|
||||
| Typst | Yes | PDF generation | ~30MB |
|
||||
| PyYAML | Yes | Config file parsing | <1MB |
|
||||
| qpdf | Optional | PDF optimization | ~5MB |
|
||||
|
||||
## Platform Support
|
||||
|
||||
This tool is designed for macOS but should work on:
|
||||
- **macOS**: Full support (10.15+)
|
||||
- **Linux**: Should work with same dependencies
|
||||
- **Windows**: Requires WSL or manual adaptation
|
||||
|
||||
## Next Steps
|
||||
|
||||
After installation:
|
||||
1. Run `make` to generate default flashcards
|
||||
2. Check `out/flashcards.pdf` for output
|
||||
3. Run `make samples` for more examples
|
||||
4. Customize with your own configuration
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
# Soroban Flashcard Generator
|
||||
|
||||
A vector-based PDF flashcard generator for learning soroban (Japanese abacus) numbers. Creates double-sided flashcards with soroban bead representations on the front and Arabic numerals on the back.
|
||||
|
||||
## Features
|
||||
|
||||
- **Pure vector graphics** - All soroban diagrams and text are rendered as vectors
|
||||
- **Configurable layouts** - Default 6 cards per US Letter page, customizable
|
||||
- **Duplex printing ready** - Automatic front/back alignment for double-sided printing
|
||||
- **Embedded fonts** - Bundled DejaVu Sans for consistent output
|
||||
- **Flexible number ranges** - Generate cards for any range or custom list
|
||||
- **macOS optimized** - Minimal dependencies, works great on Mac
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- macOS (tested on latest versions)
|
||||
- Python 3 (included with macOS)
|
||||
- Typst (PDF generation engine)
|
||||
- qpdf (optional, for linearization)
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
make install
|
||||
|
||||
# Or manually:
|
||||
brew install typst qpdf
|
||||
pip3 install pyyaml
|
||||
```
|
||||
|
||||
### Generate Flashcards
|
||||
|
||||
```bash
|
||||
# Generate default set (0-9)
|
||||
make
|
||||
|
||||
# Generate from config file
|
||||
python3 src/generate.py --config config/0-99.yaml
|
||||
|
||||
# Custom range
|
||||
python3 src/generate.py --range 0-99
|
||||
|
||||
# Custom list of numbers
|
||||
python3 src/generate.py --range "1,2,5,10,20,50,100"
|
||||
|
||||
# With shuffle
|
||||
python3 src/generate.py --range 0-99 --shuffle --seed 42
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Using Configuration Files
|
||||
|
||||
Create a YAML or JSON file with your preferences:
|
||||
|
||||
```yaml
|
||||
range: "0-99"
|
||||
cards_per_page: 6
|
||||
paper_size: "us-letter"
|
||||
orientation: "portrait"
|
||||
margins:
|
||||
top: "0.5in"
|
||||
bottom: "0.5in"
|
||||
left: "0.5in"
|
||||
right: "0.5in"
|
||||
gutter: "5mm"
|
||||
show_cut_marks: true
|
||||
show_registration: true
|
||||
font_family: "DejaVu Sans"
|
||||
font_size: "48pt"
|
||||
columns: auto
|
||||
show_empty_columns: false
|
||||
shuffle: false
|
||||
seed: 42 # For deterministic shuffling
|
||||
```
|
||||
|
||||
### Command-Line Options
|
||||
|
||||
```bash
|
||||
python3 src/generate.py [OPTIONS]
|
||||
|
||||
Options:
|
||||
--config, -c FILE Configuration file (JSON or YAML)
|
||||
--range, -r RANGE Number range (e.g., "0-99") or list (e.g., "1,2,5")
|
||||
--cards-per-page N Cards per page (default: 6, options: 4,6,8,9)
|
||||
--paper-size SIZE Paper size (default: us-letter)
|
||||
--orientation ORIENT Page orientation (portrait/landscape)
|
||||
--margins T,R,B,L Margins (e.g., "0.5in,0.5in,0.5in,0.5in")
|
||||
--gutter SIZE Space between cards (default: 5mm)
|
||||
--shuffle Shuffle the numbers
|
||||
--seed N Random seed for deterministic shuffle
|
||||
--cut-marks Show cut marks
|
||||
--registration Show registration marks for alignment
|
||||
--font-family FONT Font family (default: DejaVu Sans)
|
||||
--font-size SIZE Font size (default: 48pt)
|
||||
--columns N Soroban columns (auto or number)
|
||||
--show-empty-columns Show leading empty columns
|
||||
--output, -o FILE Output PDF path (default: out/flashcards.pdf)
|
||||
--linearize Create linearized PDF (default: true)
|
||||
```
|
||||
|
||||
## Soroban Representation
|
||||
|
||||
The soroban is rendered with:
|
||||
- **1 heaven bead** (worth 5) per column
|
||||
- **4 earth beads** (worth 1 each) per column
|
||||
- **Active beads** shown in black, moved toward the reckoning bar
|
||||
- **Inactive beads** shown in light gray, away from the bar
|
||||
- **Columns** represent place values (ones, tens, hundreds, etc.)
|
||||
|
||||
### Column Display Options
|
||||
|
||||
- `columns: auto` - Shows minimal columns needed
|
||||
- `columns: 3` - Always shows 3 columns (e.g., for 0-999)
|
||||
- `show_empty_columns: true` - Shows leading zeros
|
||||
- `show_empty_columns: false` - Suppresses leading zeros
|
||||
|
||||
## Print Settings
|
||||
|
||||
### For Best Results
|
||||
|
||||
1. **Paper**: US Letter (8.5" × 11") or A4
|
||||
2. **Margins**: Default 0.5" works with most printers
|
||||
3. **Duplex**: Long-edge binding, automatic duplex
|
||||
4. **Cut marks**: Enable with `--cut-marks` for easier cutting
|
||||
5. **Registration**: Enable with `--registration` for alignment verification
|
||||
|
||||
### Sample Configurations
|
||||
|
||||
- `config/default.yaml` - Basic 0-9 set
|
||||
- `config/0-99.yaml` - Two-digit numbers with cut marks
|
||||
- `config/3-column-fixed.yaml` - Three-digit numbers, fixed width
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
soroban-abacus-flashcards/
|
||||
├── src/
|
||||
│ └── generate.py # Main CLI tool
|
||||
├── templates/
|
||||
│ └── flashcards.typ # Typst template with soroban rendering
|
||||
├── config/
|
||||
│ ├── default.yaml # Default configuration
|
||||
│ ├── 0-99.yaml # 0-99 range config
|
||||
│ └── 3-column-fixed.yaml # 3-column fixed width config
|
||||
├── fonts/
|
||||
│ ├── DejaVuSans.ttf # Bundled font
|
||||
│ └── DejaVuSans-Bold.ttf # Bold variant
|
||||
├── out/ # Generated PDFs (created on first run)
|
||||
├── Makefile # Build automation
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
## Design Notes
|
||||
|
||||
### Soroban Number Mapping
|
||||
|
||||
Numbers are decomposed into heaven (5s) and earth (1s) beads:
|
||||
- **7** = 1 heaven bead (5) + 2 earth beads (2×1)
|
||||
- **23** = Tens: 4 earth beads (4×1), Ones: 3 earth beads (3×1)
|
||||
- **156** = Hundreds: 1 heaven + 0 earth, Tens: 1 heaven + 0 earth, Ones: 1 heaven + 1 earth
|
||||
|
||||
### Duplex Alignment
|
||||
|
||||
- Front cards are laid out left-to-right, top-to-bottom
|
||||
- Back cards are mirrored horizontally for long-edge binding
|
||||
- Registration marks (optional) help verify alignment
|
||||
- Safe margins ensure content isn't lost when cutting
|
||||
|
||||
### Vector Graphics
|
||||
|
||||
All elements are rendered as vectors using Typst's drawing primitives:
|
||||
- Beads are vector circles with stroke
|
||||
- Rods and reckoning bar are vector rectangles
|
||||
- No rasterization ensures crisp output at any scale
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "typst command not found"
|
||||
Run `make install` or `brew install typst`
|
||||
|
||||
### "qpdf command not found"
|
||||
PDF will generate but won't be linearized. Install with `brew install qpdf`
|
||||
|
||||
### Fonts not embedding
|
||||
Ensure the `fonts/` directory contains the DejaVu TTF files
|
||||
|
||||
### Misaligned duplex printing
|
||||
- Check printer duplex settings (should be long-edge)
|
||||
- Enable registration marks with `--registration`
|
||||
- Verify margins match your printer's capabilities
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
# Generate samples
|
||||
make samples
|
||||
|
||||
# Quick test
|
||||
make test
|
||||
|
||||
# Clean all outputs
|
||||
make clean
|
||||
|
||||
# Show help
|
||||
make help
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This project uses DejaVu Sans font (included), which is released under a free license. The generator code is provided as-is for educational use.
|
||||
Loading…
Reference in New Issue