Idles - Systems Architecture Report
Scope Covered
This report covers all tracked files in the repository (62 total at time of analysis), including:
- Project configuration.
- Core runtime scripts.
- Gameplay/economy systems.
- Goal/unlock systems.
- UI adapter scripts and scenes.
- Data resources (
.tres). - Technical docs and metadata/import files.
The focus below is on behavior-bearing files and how they interact.
Architecture Summary
- Global startup and singleton wiring is defined in
project.godot. - Two autoload services power the runtime:
CurrencyDatabaseandGameState. BigNumberis the numeric backbone used by currency amounts, costs, goals, production, and persistence.- Generator behavior is runtime-driven by
CurrencyGenerator, parameterized byCurrencyGeneratorDataandGeneratorBuffDataresources. - Goal-based progression uses reusable goal primitives (
GoalData,GoalRequirementData) plus unlock bindings (GeneratorUnlockGoalData) and runtime evaluator (generator_unlock_system.gd). - UI scripts are thin adapters listening to
GameStatesignals.
Core Systems
1) Numeric System (BigNumber)
File: core/big_number.gd
BigNumber stores values as mantissa + exponent (scientific notation style), normalizes them, and provides:
- Arithmetic operations (
add,subtract,multiply,divide). - In-place fast accumulation (
add_in_place) for frame-loop performance. - Safe comparisons (
compare_to,is_greater_than, etc.). - Ratio conversion for progress UI (
get_ratio). - Display formatting (
to_string_sci,to_string_suffix). - JSON-friendly serialization/deserialization.
This class is used everywhere currency values move.
2) Currency Catalog System
Files: core/currency/currency.gd, core/currency_database.gd, idles/currencies/*.tres
CurrencyDatabase scans res://idles/currencies, loads typed Currency resources, normalizes IDs, and resolves names/icons.
Current data assets:
idles/currencies/magic.tres(id = magic).idles/currencies/knowledge.tres(id = knowledge).
This creates a data-driven currency catalog that GameState, goals, and UI can query consistently.
3) Global State + Persistence (GameState)
File: core/game_state.gd
GameState is the central state authority and signal bus.
It owns:
- Current currency map by currency ID.
- Total acquired currency map by currency ID.
- Generator states (
owned,purchased_count,unlocked,available). - Generator buff levels.
- Generator buff unlocked flags.
last_save_time.
Important signals:
currency_changed.generator_state_changed.generator_buff_level_changed.generator_buff_unlocked_changed.
Persistence:
- Save path:
user://idle_save.json. - Save payload includes currencies, generator states, buff levels, buff unlocked map, and timestamp.
- Load path includes defensive sanitization and backward-compatible defaulting.
4) Generator Economy Runtime
Files: core/generator/currency_generator.gd, core/generator/currency_generator_data.gd, core/generator/currency_generator.tscn
CurrencyGenerator implements active gameplay behavior:
- Auto production cycles (
_process, cycle accumulation). - Click/hover grants with cooldown.
- Buy-one and buy-max generator purchases.
- Buff purchase logic and buff effect application.
- State registration and lookup through
GameState.
CurrencyGeneratorData provides formulas and tuning knobs:
- Exponential cost growth.
- Bulk-buy geometric cost.
- Max-affordable estimate.
- Milestone multipliers.
- Purchased-count multiplier.
- Production/cycle and production/second helpers.
- ROI-like helpers (
payback_seconds,income_to_cost_ratio).
5) Buff System
Files: core/generator/generator_buff_data.gd, idles/buffs/*.tres
Buff kinds:
- Auto production multiplier.
- Manual click multiplier.
- Resource purchase (instant grant on buff buy).
Each buff resource defines:
- Unlock rules (
unlockedand optionalunlock_goal). - Effect scaling (
base_effect,effect_increment). - Cost scaling (
base_cost,cost_multiplier). - Optional target currency and resource grant scaling.
6) Goals and Unlock Progression
Files:
core/goals/goal_requirement_data.gdcore/goals/goal_data.gdcore/generator-unlock-goals/generator_unlock_goal_data.gdcore/generator-unlock-goals/generator_unlock_system.gdidles/goals/*.tres
Key behavior:
- Goal requirements validate currency + target amount.
- Requirement completion checks total acquired currency, not current wallet.
- Unlock system evaluates goals on currency change and generator state changes.
- If a goal is met and target generator is resolvable, it sets both
unlocked = trueandavailable = true.
7) UI Adapter Layer
Files:
generator_container.gd+generator_container.tscn.generator_buff_tile.gd+generator_buff_tile.tscn.currency_label.gd+currency_tile.tscn.big_number_progress_bar.gd+big_number_progress_bar.tscn.core/generator-unlock-goals/goals_debug_ui.gd+.tscn.
These scripts primarily:
- Subscribe to
GameStateand generator signals. - Convert runtime values to UI strings/states.
- Trigger user actions (buy generator, buy buff, debug unlock).
The architecture is mostly event-driven and avoids polling for state refresh.
Scene Composition
Active Gameplay Prototype
File: docs/museums/generator_museum.tscn
It composes:
MagicGeneratorinstance.KnowledgeGeneratorinstance (initially hidden and starts locked via data).- Currency tiles for
magicandknowledge. - Goals debug UI panel.
- Runtime
GeneratorUnlockSystemnode with configured unlock goals.
Legacy/Secondary Museum
Files: docs/museums/big_number_museum.tscn, docs/museums/big_number_museum.gd
This appears to be an older/placeholder scene and not the current gameplay focus.
Data-Driven Content Snapshot
Generators
primary_generator.tres:Magic Orb, active from start, includes 3 buffs.secondary_generator.tres:Library, starts locked/unavailable.
Buffs (Magic)
magic_auto_flux.tres: auto-production buff, unlocked by default.magic_click_focus.tres: manual-click buff.magic_supply_cache.tres: resource-purchase buff.
Goals
magic_total_30.tres: reach total magic 30.magic_total_1300.tres: reach total magic 1300.generator_unlock_knowledge.tres: mapsmagic_total_30to generatorKnowledge.generator_unlock_wood.tres: mapsmagic_total_1300to generatorWood.
End-to-End Runtime Flow
project.godotautoloadsCurrencyDatabaseandGameState.CurrencyDatabasebuilds currency catalog fromidles/currencies.GameStateinitializes per-currency maps and loads save data.- Scene nodes initialize and connect to
GameStateand local gameplay signals. - Generators produce currency automatically and via click/hover paths.
- Currency updates emit
currency_changedand drive UI refresh + unlock checks. - Goal unlock evaluator may transition generator state to unlocked/available.
- Generator and buff purchases route all balance/state mutations through
GameState.
Signal Guide (Emitters and Listeners)
Custom Gameplay Signals
| Signal | Declared In | Emitted By | Emitted When | Listeners |
|---|---|---|---|---|
currency_changed(currency_id, new_amount) |
core/game_state.gd |
GameState.add_currency_by_id, GameState.spend_currency_by_id |
Any currency balance increases/decreases | CurrencyGenerator._on_currency_changed, GeneratorPanel._on_currency_changed, CurrencyTile._on_currency_changed, BigNumberProgressBar._on_currency_changed, GeneratorUnlockSystem._on_currency_changed, GoalsDebugUI._on_currency_changed |
generator_state_changed(generator_id, state) |
core/game_state.gd |
GameState.register_generator, GameState._set_generator_state |
Generator state created or changed (owned, purchased_count, unlocked, available) |
CurrencyGenerator._on_generated_state_changed, GeneratorPanel._on_generator_state_changed, GeneratorUnlockSystem._on_generator_state_changed, GoalsDebugUI._on_generator_state_changed |
generator_buff_level_changed(generator_id, buff_id, new_level) |
core/game_state.gd |
GameState.register_generator_buff, GameState.set_generator_buff_level |
Buff level created/sanitized/updated | GeneratorPanel._on_generator_buff_level_changed |
generator_buff_unlocked_changed(generator_id, buff_id, unlocked) |
core/game_state.gd |
GameState.register_generator_buff_unlocked, GameState.set_generator_buff_unlocked |
Buff unlock state created/sanitized/updated | GeneratorPanel._on_generator_buff_unlocked_changed |
purchase_completed(amount, total_owned, total_purchased, total_cost) |
core/generator/currency_generator.gd |
CurrencyGenerator.buy |
Generator purchase succeeds | GeneratorPanel._on_generator_updated |
purchase_failed(requested_amount, required_cost, available_currency) |
core/generator/currency_generator.gd |
CurrencyGenerator.buy |
Generator purchase fails for insufficient funds | GeneratorPanel._on_generator_updated |
production_tick(amount, cycle_count, total_owned) |
core/generator/currency_generator.gd |
CurrencyGenerator._grant_cycle_income |
One or more automatic production cycles complete | GeneratorPanel._on_generator_updated |
buff_purchased(buff_id, new_level, cost, cost_currency_id) |
core/generator/currency_generator.gd |
CurrencyGenerator.buy_buff |
Buff purchase succeeds | GeneratorPanel._on_generator_updated |
buff_purchase_failed(buff_id, required_cost, cost_currency_id) |
core/generator/currency_generator.gd |
CurrencyGenerator.buy_buff |
Buff purchase fails for insufficient funds | GeneratorPanel._on_generator_updated |
goal_achieved(goal_id, target_generator_id) |
core/generator-unlock-goals/generator_unlock_system.gd |
GeneratorUnlockSystem._evaluate_goal |
Unlock goal transitions target generator to unlocked+available | None currently (available for gameplay/UI hooks) |
buy_pressed(buff_id) |
generator_buff_tile.gd |
GeneratorBuffTile._on_buy_button_pressed |
User presses buff buy button in a buff row | GeneratorPanel._on_buy_buff_pressed |
Built-In Godot Signals Wired In This Project
| Source Signal | Connected In | Listener Method | Purpose |
|---|---|---|---|
Area2D.mouse_entered |
core/generator/currency_generator.tscn |
CurrencyGenerator._on_area_2d_mouse_entered |
Enter generator hover zone; mark hover true and show generator panel |
Area2D.mouse_exited |
core/generator/currency_generator.tscn |
CurrencyGenerator._on_area_2d_mouse_exited |
Exit generator hover zone; mark hover false and hide generator panel |
BuyOneButton.pressed |
generator_container.tscn |
GeneratorPanel._on_buy_pressed |
Buy one generator |
BuyMaxButton.pressed |
generator_container.tscn |
GeneratorPanel._on_buy_max_pressed |
Buy max affordable generators |
GeneratorContainer.mouse_entered |
generator_container.tscn |
GeneratorPanel._on_mouse_entered |
Intended hover hook on panel container (method currently missing) |
GeneratorContainer.mouse_exited |
generator_container.tscn |
GeneratorPanel._on_mouse_exited |
Intended hover hook on panel container (method currently missing) |
BuyButton.pressed |
generator_buff_tile.tscn |
GeneratorBuffTile._on_buy_button_pressed |
Emit tile-level buy_pressed custom signal |
DebugIncomeButton.pressed |
currency_tile.tscn |
CurrencyTile._on_debug_income_button_pressed |
Add debug income to the tile currency |
Button.pressed (runtime-created unlock button) |
core/generator-unlock-goals/goals_debug_ui.gd |
GoalsDebugUI._on_unlock_pressed (bound with goal id) |
Manual debug unlock when a goal is ready |
Common Signal Chains
- Currency gain/spend chain: generator or debug action mutates
GameStatecurrency,GameStateemitscurrency_changed, UI widgets and unlock systems recompute and redraw. - Generator purchase chain: panel button triggers
CurrencyGenerator.buy, generator updatesGameStatestate, generator emits purchase signal, panel refreshes stats and buttons. - Buff purchase chain: buff tile emits
buy_pressed, panel callsCurrencyGenerator.buy_buff, generator updates buff level/unlock and optionally grants currency,GameStateemits buff/currency/state signals, panel and other listeners refresh. - Goal unlock chain:
currency_changedtriggers unlock evaluator, evaluator sets generatorunlocked/available, emitsgoal_achieved(goal_id, target_generator_id),GameStateemitsgenerator_state_changed, generator and UI become interactable/visible.
Key Findings and Risks
project.godothas no explicitrun/main_sceneentry, so startup scene is not pinned in tracked config.- Save/load is only partially wired:
load_game()runs at startup, butsave_game()is not invoked anywhere else in the repository. currency_label.gdandbig_number_progress_bar.gdreferenceGameState.GOLD_CURRENCY_ID, but that constant does not exist incore/game_state.gd.generator_container.tscnconnectsmouse_entered/mouse_exitedto methods that do not exist ingenerator_container.gd.generator_unlock_wood.trestargets generator IDWood, but no generator with that ID appears in current runtime scene/content, so this goal is currently non-functional.KnowledgeGeneratorvisibility logic may be inconsistent becausecurrency_generator.gdsetsvisible = truewhenever its generator state changes.- Two buffs are configured locked with no unlock-goal path, so they remain permanently inaccessible under current logic.
core/generator-unlock-goals/TECH_SPEC.mdcontains some outdated assumptions relative to current.tres-based implementation.
Additional Notes
.uidfiles are identity metadata used by Godot and contain no runtime logic.icon.svgandicon.svg.importare standard icon/import metadata.- Root config files (
.editorconfig,.gitattributes,.gitignore) are minimal and conventional.