Both jobs land on the same self-hosted runner. Run 129 segfaulted odin test in build while windows was mid (uncached) SDK download/ splat at the same time; odin check passed and the test suite reproduces fine in isolation, so this is resource contention from running concurrently for the first time, not a code or toolchain bug. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
79 lines
5.9 KiB
Markdown
79 lines
5.9 KiB
Markdown
# HanjaKanaMun - Project Plan
|
|
|
|
## Overview
|
|
Odin + raylib multilingual memory card game for learning Japanese (Hiragana/Katakana), Korean (Hangul), and Thai scripts.
|
|
|
|
Commands (see `justfile`): `just run`, `just check`, `just test`, `just package <version>`, `just package-windows <version>`
|
|
|
|
## Current Status
|
|
|
|
### Completed
|
|
- [x] Code split into modules under `src/` (themes, assets, audio, ui, card, decks, memory, profile, screens)
|
|
- [x] `.odin` files tracked in git (`.gitignore` used to ignore `*.odin`)
|
|
- [x] Fonts: M PLUS Rounded 1c (UI + kana), Jua (Hangul), Mali (Thai), all OFL, loaded via `LoadFontEx` with explicit codepoints
|
|
- [x] Per-language themes (`themes.Theme`) with flag-based card backs: Japan (Hinomaru), Korea (Taegukgi), Thailand (Trairong)
|
|
- [x] Card flip animation (art rendered to textures and squashed), lift, shadow, lighting; matched cards pulse; cards are dealt in at game start
|
|
- [x] Sound effects synthesized in code (flip, match, mismatch, win, button click), no audio files needed
|
|
- [x] Decks: Hiragana (46), Katakana (46), Hangul basic jamo (24), Thai consonants (42); symbol ↔ reading pairs
|
|
- [x] Difficulty levels: Easy 3x4 (6 pairs), Normal 4x6 (12), Hard 4x8 (16)
|
|
- [x] Keyboard play: arrows / WASD / hjkl move focus, Enter/Space flips; number keys pick menu entries; Esc goes back (quits from main menu)
|
|
- [x] High scores: best moves, best time and games played per deck + difficulty, plus last difficulty, saved as JSON in the user data folder
|
|
- [x] Screen fade-in transitions
|
|
- [x] Win panel with best score / "New best!", Play Again (Enter) / Menu
|
|
- [x] Tooling: justfile, ols/odinfmt config for neovim, tests, Gitea CI (build/test, Windows cross-build, tagged releases)
|
|
|
|
### Ideas / Next
|
|
- [ ] Hangul syllable blocks deck (e.g. 가 ga, 나 na), Thai vowels (needs care: combining marks)
|
|
- [ ] Hiragana ↔ katakana pairing mode, dakuten (が, ぱ…) deck
|
|
- [ ] Settings: sound on/off, volume
|
|
- [ ] Test the Windows build on a real machine
|
|
- [ ] macOS release build (would need a macOS runner or osxcross)
|
|
|
|
## Known Issues / Gotchas
|
|
1. **Font glyphs must be listed**: raylib only bakes the codepoints passed to `LoadFontEx`. Any new non-ASCII text needs its characters added in `assets.codepoints_for` (or the `EXTRA_*` strings), otherwise it renders as `?`. The `fonts_cover_every_deck_character` test checks deck text.
|
|
2. **Old font failure root cause**: `DroidSansJapanese.ttf` was a GitHub HTML page saved from a blob URL, not a font. Always download fonts from raw URLs and check them with `file`.
|
|
3. **Thai shaping**: raylib does no text shaping, so Thai combining vowels/tone marks would be misplaced. Thai cards use standalone consonants; Thai UI text avoids marks (win message is English).
|
|
4. Tests share the memory game's global state, so they must run single-threaded (`just test` sets `ODIN_TEST_THREADS=1`).
|
|
5. The game changes directory to the executable's folder at startup so `assets/` is found from anywhere.
|
|
6. **Windows builds are cross-compiled**: Odin can't link Windows binaries on Linux, so `just windows` builds objects with `-build-mode:obj` and links with `lld-link` against an xwin SDK. The VC runtime is linked statically; only Windows system DLLs are needed. New Odin core usage can need new import libs (e.g. `ole32.lib` for `os.user_data_dir`); the CI `windows` job catches this. Not yet tested on a real Windows machine.
|
|
7. **Odin constant arrays can't be indexed at runtime**: lookup tables (`DECKS`, `LAYOUTS`, …) are `@(rodata)` globals instead of `::` constants.
|
|
8. **Profile memory**: `profile` always allocates from the heap allocator, because the test runner frees each test's allocator afterwards.
|
|
9. **CI jobs share one self-hosted runner**: `build` and `windows` in `gitea-build.yaml` land on the same machine. Running them concurrently once segfaulted `odin test` while `windows` was mid-SDK-download, so `windows` now runs with `needs: build` to avoid the contention.
|
|
|
|
## File Structure
|
|
```
|
|
HanjaKanaMun/
|
|
├── AGENTS.md # Project plan (this file)
|
|
├── README.md
|
|
├── justfile # build/run/check/test/package/windows recipes
|
|
├── ols.json # ols language server settings (neovim)
|
|
├── odinfmt.json # odinfmt formatter settings (4 spaces, LF)
|
|
├── .gitea/
|
|
│ ├── actions/setup/ # shared CI toolchain setup (apt, Odin, just)
|
|
│ └── workflows/
|
|
│ ├── gitea-build.yaml # check + test + build, and Windows cross-build, on main/develop
|
|
│ └── gitea-release.yaml # on tags v*: Linux + Windows packages, package registry upload, Gitea release
|
|
├── main.odin # Window/audio setup, screen state machine, transitions
|
|
├── src/
|
|
│ ├── themes/themes.odin # Theme struct, flag colors, Screen/Flag enums, layout constants
|
|
│ ├── assets/assets.odin # Font styles and codepoint lists, font loading
|
|
│ ├── audio/audio.odin # Synthesized sound effects, play()
|
|
│ ├── ui/ui.odin # Text helpers, buttons (with hotkeys), hover cursor
|
|
│ ├── card/card.odin # Card struct, flag card-back art, face textures, flip/deal animation
|
|
│ ├── decks/decks.odin # Languages, decks and their entries (symbol, reading, hint)
|
|
│ ├── memory/memory.odin # Memory game state, logic, keyboard focus, drawing
|
|
│ ├── profile/profile.odin # Best scores and settings, JSON in the user data folder
|
|
│ └── screens/screens.odin # Main menu and language menus
|
|
├── tests/
|
|
│ ├── memory_test.odin # Decks, font coverage, game rules, layout, keyboard focus, card animation
|
|
│ └── profile_test.odin # Score records, JSON round trip, win recording
|
|
└── assets/ # Fonts (+ OFL license files)
|
|
```
|
|
|
|
## Notes
|
|
- NO rm -rf or starting over
|
|
- Make small, incremental changes
|
|
- Test after each change (`just check`, `just test`, then `just run`)
|
|
- Keep existing functionality working
|
|
- Commit after each working step
|