A web-based codex for Brotato, built from decompiled game data.
Features: price / attack speed / curse calculator, multiple language support, and more QoL features.
- Data pipeline: Python 3 — parses Godot
.tresresource files, translates effect text, generates JSON + icon assets - Frontend: Vue 3 + Element Plus + Vite (uses
pnpm) - Styling: Scoped CSS with dark/light theme toggle
- GDRE Tools to decompile the game
- Remember to choose "Add .pck" to decompile both the base game and DLC data at once
# 1. Decompile game with GDRE to a directory, e.g. D:\brotato\decompiled
# The directory should contain: .assets/, weapons/, items/, dlcs/, effects/, etc.
# 2. Clone this repo into the decompiled directory
cd D:\brotato\decompiled
git clone https://github.com/mojimoon/brotato codex
# 3. Pre-analyze missing translations
cd codex/translations
python analyze.py
# Outputs: codex/translations/merged_analysis.json
# 4. Start the translation fix web tool
pnpm install
pnpm dev
# Opens at http://localhost:3000
# 5. In the web tool: load merged_analysis.json, match translations, export
# Exported file goes to: codex/public/data/translations_merged.json
# 6. Generate the full game data
cd D:\brotato\decompiled
cd codex
python main.py
# Outputs: codex/public/data/brotato_data.json
# codex/public/icons/
# 7. Build the codex website
pnpm install
pnpm build
# Output: codex/dist/root/
├── .assets/ # Game resources (translations CSV, images, etc.)
├── weapons/ # Base weapons (melee/, ranged/)
├── items/ # Base items + characters
├── effects/ # Effect class implementations
├── dlcs/dlc_1/ # DLC1 data
└── codex/ # This repo
├── main.py # Data pipeline: .tres → JSON + icons
├── public/data/
│ ├── brotato_data.json # Generated game data
│ └── translations_merged.json # Manual translation fixes
├── src/App.vue # Vue frontend
└── translations/ # Translation fix toolchain
├── analyze.py # Scans for missing translation keys
└── web/ # Vue app for manual translation matching
- Loads translations from
.assets/resources/translations/translations.csv(base game) anddlcs/dlc_1/translations/translations.csv(DLC) - Optionally loads
translations_merged.jsonfor manually fixed entries - Parses every weapon, item, and character
.tresfile with a custom parser (not Godot runtime) - Renders effect text by replicating Godot's
Effect.get_text()→Text.text()pipeline:- Resolves translation key (
text_keyorkey, uppercased) - Builds args via each effect subclass's
get_args()logic - Applies
custom_argsoverrides (value, sign, format) - Formats with operator (+), percent (%), and color spans
- Resolves translation key (
- Copies all referenced icon files to
public/icons/
analyze.pyscans all.treseffect files, extracts translation keys, cross-references with CSV, and outputsmerged_analysis.json— a categorized list of missing keys with candidate strings- The web tool (
pnpm dev) lets you visually match missing keys to translations and export atranslations_merged.json main.pypicks up this file and fills in the gaps
extra.spawn_cooldown— already in seconds, do NOT divide by 60structure_stats.cooldown— in frames (60 fps), divide by 60weapon_stats.cooldown— in frames (60 fps), divide by 60
- Two code paths exist:
_build_effect_args_and_signs()(legacy) andrender_effect_text()(active). Changes must be applied to both. text_key = "[EMPTY]"effects are filtered out entirelystat_scaled = "different_item"maps totr("ITEM")(nottr("DIFFERENT_ITEM"))spawn_cooldown = -1is a sentinel meaning "use stats file cooldown"- Icon syntax:
<icon>short_key</icon>(e.g.,<icon>ranged_damage</icon>) — Python generates it, Vue renders as<img> - Stat icon prefix: effects with
keystarting withstat_get an icon prefix; others get・for alignment
- Left panel: grid with
repeat(auto-fill, minmax(90px, 1fr))layout - Right panel: detail view with independent scroll
- Effect items use two flex children (
eff-prefix+eff-text) to prevent line wrapping - Theme toggle:
isDarkref +watchaddslight-themeclass to<html>and<body> - Tab icons: Aim (weapons), Box (items), User (characters) from
@element-plus/icons-vue - Language switch: el-dropdown with text content (not
:iconprop, which requires a component) htmlmust have same background asbodyto prevent color bleed on wide screens
