This guide will help you set up a development environment, understand the codebase structure, and contribute to the Torena Sim project. Whether you're updating game data, fixing bugs, or adding new features, this document provides the information you need.
Before you begin, ensure you have the following installed:
- Node.js v24 or later
- bun (the project's package manager, specified in
packageManagerfield)
The project ships with pre-extracted JSON data in src/modules/data/, so you can run the app without the game database. If you want to re-extract data from the source database:
Option A: Download via script (recommended)
bun run db:fetch <version-id> # e.g. 10004010This downloads master.mdb into db/master.mdb, which the extraction scripts detect automatically.
Option B: Copy from a local game installation
Copy your master.mdb file to db/master.mdb at the project root. See scripts/README.md for platform-specific paths.
The db/ directory is gitignored.
umalator-global/
├── src/ # Application source
│ ├── main.tsx # Entry point (HashRouter, theme provider)
│ │
│ ├── routes/ # React Router page routes
│ │ ├── root.tsx # Root layout and route definitions
│ │ ├── _simulation.tsx # Simulation section layout
│ │ ├── _simulation/
│ │ │ ├── home.tsx # Compare tools (default page)
│ │ │ ├── skill-bassin.tsx # Skill basin comparison
│ │ │ └── uma-bassin.tsx # Uma basin comparison
│ │ ├── runners.tsx # Runners section layout
│ │ ├── runners/
│ │ │ ├── home.tsx # Runner library list
│ │ │ ├── new.tsx # Create new runner
│ │ │ └── $runnerId.edit.tsx # Edit existing runner
│ │ ├── skill-planner.tsx # Skill planner page
│ │ └── stamina-calculator.tsx # Stamina calculator page
│ │
│ ├── lib/ # Core libraries
│ │ ├── sunday-tools/ # Race simulation engine
│ │ │ ├── common/ # Race, runner, spurt calculator, observer
│ │ │ ├── course/ # Course data and definitions
│ │ │ ├── conditions/ # Approximate and special conditions
│ │ │ ├── health/ # HP/stamina policies
│ │ │ ├── poskeep/ # Position keeping (analytical pacer)
│ │ │ ├── runner/ # Runner types, definitions, utilities
│ │ │ ├── shared/ # Shared definitions, region, random
│ │ │ ├── skills/ # Skill types, definitions, parser, policies
│ │ │ │ └── parser/ # Condition parser and matcher
│ │ │ └── simulator.types.ts # Top-level simulator types
│ │ ├── feature-flags.ts # Feature flag utilities
│ │ └── utils.ts # General utilities (cn, etc.)
│ │
│ ├── modules/ # Feature modules
│ │ ├── simulation/ # Simulation UI and orchestration
│ │ │ ├── simulators/ # Compare strategies (skill, uma, vacuum)
│ │ │ ├── hooks/ # Simulation React hooks
│ │ │ ├── stores/ # Zustand stores (compare, skill-basin, uma-basin)
│ │ │ ├── tabs/ # Result visualization tabs
│ │ │ ├── compare.types.ts # Compare type definitions
│ │ │ └── types.ts # Module types
│ │ │
│ │ ├── skills/ # Skill system
│ │ │ ├── components/ # Skill UI components
│ │ │ ├── store.ts # Skill selection state
│ │ │ ├── query.ts # Skill data queries
│ │ │ ├── filters.ts # Skill filtering logic
│ │ │ ├── effects-query.ts # Skill effects queries
│ │ │ ├── conditions.ts # Condition utilities
│ │ │ ├── skill-relationships.ts # Skill relationship mapping
│ │ │ ├── icons.ts # Skill icon handling
│ │ │ └── utils.ts # Skill utilities
│ │ │
│ │ ├── racetrack/ # Course visualization
│ │ │ ├── components/ # Track UI components
│ │ │ ├── hooks/ # Track-related hooks
│ │ │ ├── courses.ts # Course data utilities
│ │ │ ├── labels.ts # Track labels
│ │ │ └── types.ts # Track types
│ │ │
│ │ ├── runners/ # Runner configuration
│ │ │ ├── components/ # Runner UI components
│ │ │ ├── ocr/ # OCR import functionality
│ │ │ ├── hooks/ # Runner hooks
│ │ │ ├── data/ # Runner data utilities
│ │ │ └── utils.ts # Runner utilities
│ │ │
│ │ ├── skill-planner/ # Skill planner feature
│ │ │ ├── components/ # Planner UI components
│ │ │ ├── hooks/ # Planner hooks
│ │ │ ├── skill-planner.store.ts # Planner state
│ │ │ ├── optimization-engine.ts # Skill optimization engine
│ │ │ ├── optimizer.ts # Optimizer logic
│ │ │ ├── simulator.ts # Planner simulation runner
│ │ │ ├── cost-calculator.ts # SP cost calculator
│ │ │ └── types.ts # Planner types
│ │ │
│ │ ├── tutorial/ # Tutorial system
│ │ │ ├── steps/ # Tutorial step definitions
│ │ │ └── types.ts # Tutorial types
│ │ │
│ │ └── data/ # Game data files (JSON)
│ │ ├── skills.json # Unified skill data
│ │ ├── course_data.json # Course/track data
│ │ ├── umas.json # Uma musume character data
│ │ ├── tracknames.json # Track name translations
│ │ ├── icons.json # Icon data
│ │ ├── skill-types.ts # Skill type definitions
│ │ ├── skills.ts # Skill data access layer
│ │ └── gametora/ # Gametora sourced data
│ │
│ ├── components/ # Shared UI components
│ │ ├── ui/ # shadcn/ui components
│ │ ├── bassin-chart/ # Basinn chart components
│ │ ├── race-settings/ # Race configuration components
│ │ ├── tutorial/ # Tutorial UI components
│ │ └── ... # Modals, overlays, presets, etc.
│ │
│ ├── store/ # Global Zustand stores
│ │ ├── runners.store.ts # Runner state management
│ │ ├── runner-library.store.ts # Runner library state
│ │ ├── settings.store.ts # Application settings
│ │ ├── ui.store.ts # UI state (modals, panels)
│ │ ├── tutorial.store.ts # Tutorial state
│ │ └── race/
│ │ └── preset.store.ts # Race preset state
│ │
│ ├── workers/ # Web Workers
│ │ ├── simulator.worker.ts # Single race simulations
│ │ ├── skill-basin.worker.ts # Skill basin comparisons
│ │ ├── uma-basin.worker.ts # Uma basin comparisons
│ │ ├── skill-single.worker.ts # Single skill simulations
│ │ ├── skill-planner.worker.ts # Skill planner worker
│ │ ├── ocr.worker.ts # OCR processing
│ │ ├── pool/ # Worker pool management
│ │ └── utils.ts # Worker utilities
│ │
│ ├── providers/ # React context providers
│ │ └── theme/ # Theme provider (light/dark)
│ │
│ ├── layout/ # Layout components
│ │ ├── left-sidebar.tsx # Left sidebar layout
│ │ └── runner-editor-layout.tsx # Runner editor layout
│ │
│ ├── hooks/ # Shared React hooks
│ │ └── useBreakpoint.ts # Responsive breakpoint hook
│ │
│ ├── i18n/ # Internationalization
│ │ ├── index.ts # i18next setup
│ │ └── lang/ # Language files (EN/JA)
│ │
│ ├── utils/ # Utility functions
│ ├── data/ # App-level data
│ │ └── changelog.ts # Changelog entries
│ │
│ ├── app.css # Application styles
│ └── styles.css # Global / Tailwind styles
│
├── scripts/ # Data extraction and debug scripts
│ ├── extract-all.ts # Run all extractions
│ ├── extract-skills.ts # Extract skill data
│ ├── extract-uma-info.ts # Extract uma data
│ ├── extract-course-data.ts # Extract course data
│ ├── fetch-master-db.ts # Download master.mdb
│ ├── debug-skill-compare.ts # Skill comparison debugging
│ ├── runner-compare.ts # Runner comparison script
│ ├── runner-config.schema.ts # Runner config schema (Zod)
│ ├── lib/ # Shared script libraries
│ │ ├── database.ts # SQLite database helpers
│ │ └── shared.ts # Shared utilities
│ ├── runners/ # Runner configuration files
│ ├── skill-lists/ # Skill list presets
│ ├── legacy/ # Legacy Perl scripts (reference only)
│ └── README.md # Script documentation
│
├── courseeventparams/ # Course event parameter JSONs
│ └── [course files].json # Course geometry data
│
├── docs/ # Documentation
│ ├── quick-reference.md # Race mechanics quick reference
│ ├── race-mechanics.md # Detailed race mechanics
│ ├── simulator-patterns.md # Simulator design patterns
│ └── ... # Additional documentation
│
├── public/ # Static assets
│
└── Configuration files
├── package.json # Dependencies and scripts
├── tsconfig.json # TypeScript configuration
├── vite.config.ts # Vite build configuration
├── eslint.config.js # ESLint (flat config) linter configuration
├── eslint-rules/ # Project-local ESLint rules (React/Zustand)
├── .oxfmtrc.json # oxfmt formatter configuration
├── .editorconfig # Editor configuration
├── components.json # shadcn/ui configuration
└── .env.example # Environment variable template
git clone https://github.com/jalbarrang/umalator-global.git
cd umalator-global
bun installbun run devDefault port is 5173. Open http://localhost:5173 in your browser.
The repo ships with pre-extracted JSON data, so this step is only needed when updating data after a game patch.
Fetch the latest database:
bun run db:fetchExtract all data at once (merge mode, recommended):
bun run extract:allMerge mode (the default) updates entries from master.mdb while preserving future/datamined content not yet in the database.
Full replacement mode (removes future content):
bun run extract:all -- --replaceExtract individual data files:
bun run extract:skills # Unified skill data
bun run extract:uma-info # Uma musume data
bun run extract:course-data # Course/track dataAll scripts support --replace for full replacement mode. See scripts/README.md for detailed documentation.
The build uses Vite with the following plugins (vite.config.ts):
- @vitejs/plugin-react: React support
- @tailwindcss/vite: Tailwind CSS integration
- vite-tsconfig-paths: Resolves TypeScript path aliases in both app and worker code
Path Aliases (defined in tsconfig.json, resolved by vite-tsconfig-paths):
@/*→./src/*@scripts/*→./scripts/*@workers/*→./src/workers/*
import { useSettingsStore } from '@/store/settings.store';
import { Race } from '@/lib/sunday-tools/common/race';Feature Flags:
Feature flags are managed via environment variables prefixed with VITE_FEATURE_. They are accessible at runtime via import.meta.env. See .env.example for available flags.
- React 19 with React Router v7 (HashRouter)
- TypeScript with strict mode
- Vite 7 for builds and dev server
- Tailwind CSS v4 for styling
- shadcn/ui (base-nova style) with Base UI React primitives
- Zustand for state management
- Immer for immutable state updates
- i18next for internationalization (EN/JA)
- Recharts for chart visualizations
- Zod for schema validation
- Vitest for unit tests
- ESLint (flat config, with
eslint-plugin-unicorn) for linting - oxfmt for formatting
- Lucide React for icons
src/main.tsx sets up the React root with:
HashRouterfor client-side routingThemeStoreProviderfor light/dark mode- Immer
MapSetplugin - i18n initialization
src/routes/root.tsx is the root layout component containing:
- Top-level navigation tabs (Compare tools, Skill Planner, Runners)
- React Router
<Routes>configuration - Global UI elements (toaster, modals, theme toggle, tutorial)
| Route | Component | Description |
|---|---|---|
/ |
SimulationHome |
Compare tools (default) |
/skill-bassin |
SkillBassin |
Skill basin comparison |
/uma-bassin |
UmaBassin |
Uma basin comparison |
/runners |
RunnersHome |
Runner library |
/runners/new |
RunnersNew |
Create new runner |
/runners/:runnerId/edit |
RunnersEdit |
Edit runner |
/skill-planner |
SkillPlanner |
Skill planner |
The core race simulation engine lives in src/lib/sunday-tools/. This is a self-contained library implementing Uma Musume race mechanics:
common/:Race,Runner,SpurtCalculator,RaceObservercourse/: Course data loading and definitionsconditions/: Skill activation condition evaluationhealth/: HP/stamina consumption policiesposkeep/: Position keeping with analytical pacingrunner/: Runner type definitions and utilitiesskills/: Skill types, parser, condition matching, activation policies
See src/lib/sunday-tools/README.md for simulation mode documentation and docs/quick-reference.md for implemented race mechanics.
The simulation module connects the engine to the UI:
simulators/: Compare strategies (skill-compare.ts,vacuum-compare.ts,skill-planner-compare.ts)hooks/: React hooks for running simulations (compare, skill basin, uma basin)stores/: Zustand stores for simulation statetabs/: Result visualization tab components
Global Stores (src/store/):
runners.store.ts— active runner configurationrunner-library.store.ts— saved runner librarysettings.store.ts— application settingsui.store.ts— UI state (modals, panels)tutorial.store.ts— tutorial progressrace/preset.store.ts— race presets
Module Stores are co-located with their modules (e.g., simulation/stores/, skills/store.ts, skill-planner/skill-planner.store.ts).
Simulations run in background threads to keep the UI responsive:
simulator.worker.ts— single race simulationsskill-basin.worker.ts— skill basin comparisonsuma-basin.worker.ts— uma performance analysisskill-single.worker.ts— single skill simulationsskill-planner.worker.ts— skill planner optimizationocr.worker.ts— OCR image processingpool/— worker pool management for parallel simulations
src/components/ui/ — shadcn/ui components (Button, Dialog, Select, Tabs, etc.) configured via components.json.
src/components/bassin-chart/ — basinn chart components for skill efficacy visualization.
src/components/race-settings/ — race condition selectors (ground, weather, season, time of day).
src/components/tutorial/ — tutorial overlay and popover system.
-
Start the dev server:
bun run dev
-
Check for TypeScript errors:
bun run typecheck
-
Run the linter:
bun run lint
-
Fix lint issues automatically:
bun run lint:fix
-
Format code:
bun run format
-
Check formatting without writing:
bun run format:check
-
Run unit tests:
bun run test -
Build for production:
bun run build
Formatting is enforced by oxfmt (.oxfmtrc.json):
- 2 spaces for indentation
- Single quotes
- Semicolons required
- 100 character line width
- LF line endings
Linting is enforced by ESLint using its flat config (eslint.config.js). It layers
@eslint/js, typescript-eslint, eslint-plugin-react, eslint-plugin-react-hooks,
eslint-plugin-jsx-a11y, and eslint-plugin-unicorn (the unopinionated preset, with the
finicky/stylistic rules turned off), plus the project-local react-props rules in
eslint-rules/.
TypeScript strict mode is enabled. Use functional React components with hooks. Style with Tailwind CSS utility classes. Use path aliases for imports.
- Check if the effect type exists in
src/lib/sunday-tools/skills/ - Add effect handling in the appropriate simulation file
- Update condition parsing if needed in
src/lib/sunday-tools/skills/parser/ - Add or update tests in corresponding
*.test.tsfiles - Test with known skills that use the effect
- Create or modify components in the appropriate module directory
- Update Zustand stores if state management is needed
- Use shadcn/ui primitives from
src/components/ui/where possible - Use Tailwind CSS for styling
- Ensure the feature works with the web worker architecture if it involves simulations
- Ensure
courseeventparams/has the latest course geometry JSONs - Run the extraction:
bun run extract:course-data- Verify course geometry in the visualization
- Test skill activations on the updated course
Run with Vitest:
bun run test # Run once
bun run test:watch # Watch modeAdd tests in *.test.ts files alongside the code they test.
- Simulations complete without errors
- Results are consistent with expected race behavior
- UI is responsive and doesn't freeze
- Skill activations appear correct on the chart
- Statistics (min/median/mean/max) are reasonable
- Changes work in both development and production builds
PR Checks (.github/workflows/pr-checks.yml):
Runs on pull requests to main:
- TypeScript type checking (
bun run typecheck) - Linting (
bun run lint) - Production build validation (
bun run build)
Both workflows use Bun with frozen lockfile.
The project deploys to Cloudflare Pages (https://torena-sim.pages.dev) via .github/workflows/deploy-cloudflare.yml.
- Deploys automatically on pushes to
main - Uses Bun + the Rust/wasm toolchain to build the engine
- Reads
VITE_PUBLIC_POSTHOG_KEYandVITE_PUBLIC_POSTHOG_HOSTfrom repository variables at build time
The old GitHub Pages and Netlify URLs now serve a static 301 redirect to the canonical Cloudflare domain.
-
Ensure code quality:
bun run typecheck # No TypeScript errors bun run lint # No linting errors bun run format:check # Code is formatted bun run test # Tests pass
-
User-facing changes use Conventional Commits (
feat:,fix:, etc.) so they appear in the in-app changelog after release. Do not editCHANGELOG.md— deploy CI regenerates it; locally runbun run changelog:generateafter fetching tags. -
Test thoroughly:
- Run simulations with your changes
- Check for performance regressions
- Test multiple running styles, courses, and skill types
-
Create a pull request:
- Describe what you changed and why
- Include test cases or examples
- Reference any related issues
Be prepared to:
- Explain your implementation choices
- Make requested changes
- Provide additional testing if needed
"Cannot find module":
- Run
bun installto ensure all dependencies are installed - Check that import paths are correct
- Verify path aliases are configured in
tsconfig.json
"Failed to open database":
- Verify the file path is correct
- Ensure the game is not running (file may be locked)
- Check file permissions
Empty or invalid JSON:
- Verify
master.mdbis from the current game version - Check console output for script errors
Worker thread crashes:
- Check browser console for error messages
- Verify all data files in
src/modules/data/are valid JSON - Test with default parameters to isolate the issue
Simulations freeze:
- Check for infinite loops in simulation code
- Verify stamina is sufficient for the course
- Use the development build for detailed error messages
Port already in use:
- Vite will automatically try the next available port
- Or specify a port:
bun run dev -- --port 3000
Hot reload not working:
- Try restarting the dev server
- Clear browser cache
scripts/README.md— data extraction script documentationsrc/lib/sunday-tools/README.md— simulation engine documentationdocs/quick-reference.md— race mechanics quick referencedocs/race-mechanics.md— detailed race mechanicsdocs/simulator-patterns.md— simulator design patterns
The simulator is based on the original Umalator project:
- Simulator Engine: github.com/alpha123/uma-skill-tools
- UI Components: github.com/alpha123/uma-tools
See README.md for full acknowledgements.
Thank you for contributing to Torena Sim!