tarinai/docs/ARCHITECTURE.md
2026-06-24 13:48:22 +09:00

6.7 KiB

Architecture

Build target: static browser page. No bundler. Globals and ordered deferred scripts are intentional. Current inspected version: 15.24.33.

Load order

app_manifest.json owns CSS/JS order. Regenerate index.html and service-worker.js with python3 scripts/generate_app_files.py after version/order changes. js/version.js exposes TARINAI_APP.version, cache name, and query helper.

The old css/styles.css compatibility shim and js/ui_family.js split marker have been removed. The family tree entry point now starts at ui_family_data.js and continues through async/layout/path/render modules.

Runtime objects

  • World: constructor in js/world.js; methods split into view, family/social, combat/effects, environment, spatial/budget, ants, update, placement/log, bootstrap.
  • Tarinai: constructor in js/tarinai.js; methods split into identity/social, disease/nest, item effects, needs/items, social/move/life, render.
  • Behavior text is composed from behavior, needs, tied needs, ActionSpec metadata, and forced-request cause metadata; stored explicit live text remains the display fallback to avoid player-visible wording churn.
  • Item: item state, lifecycle, scaling, and field rendering in js/items.js.
  • Effect: transient visuals in js/sim_core.js; combat/weather/food effects are spawned through World helpers.
  • TarinaiEvents: global event bus for logs, terrain dirtiness, audio failures, phase/performance changes.
  • TarinaiPerformance: FPS quality manager; provides effect caps, ant stride, terrain redraw cadence, UI intervals.
  • TarinaiInputMode: input classification and mobile-mode state. UI code reads this manager instead of duplicating touch heuristics.
  • TarinaiWeatherSystem: weather transitions and rain-spawned water item creation. Rain overlay drawing remains in render.js.

Startup path

main.js owns the user-visible boot sequence:

  1. Start the loading showcase and preload the initial sprite/image set through loadImages.
  2. Bind UI, apply the default garden field layout, reset the world, and select observe.
  3. Render logs, family archive, first frame, and stats.
  4. Start deferred background image loading, enter requestAnimationFrame(loop), and hide the loading screen.
  5. Register service-worker.js with updateViaCache: "none" after window load.

Data ownership

  • js/data.js: base item/tool definitions, TOOL_CATEGORIES, config, image metrics, field presets.
  • js/item_visual_registry.js: canonical item visual descriptors used by field drawing and generated tool-icon previews.
  • js/food_registry.js: food/medicine semantics such as labels, serving classes, decay multipliers, and hygiene penalties.
  • js/disease_registry.js: disease labels, flags, display metadata, cure-rule notes, and mystery-drug eligibility.
  • js/input_mode_manager.js: touch/mobile classification, mobile mode persistence, and gesture capability policy.
  • js/weather_system.js: weather state transitions and rain-water item spawning.
  • js/text_catalog.js: Japanese UI copy/tooltips. Keep JS strings escaped where existing style uses escapes.
  • js/effect_registry.js: item-effect labels, colors, modifiers, exclusivity/removal metadata, behavior callbacks (onApply, onTick, onRemove), direct eating context, and random-effect candidates.
  • js/sound_pack.js: canonical sound metadata: IDs, categories, gain multipliers, cooldowns, optional sample paths, and ID-to-category mapping.
  • FIELD_TYPES in js/data.js: cage/garden/park field labels, responsive heights, world scale, starting population, and initial grass.

State loops

main.js starts asset preload, world bootstrap, animation loop, deferred image loading, service-worker registration. World.update(dt) advances time, weather, items, ants, Tarinai, effects, budgets, terrain dirtiness. render() draws cached background/terrain, visible entities, weather overlay, cards, HUD, and debug overlays.

World time is CONFIG.dayLength seconds per day. Version 15.24.33 uses 120 seconds/day and weather changes every 46-96 seconds. The phase boundary rules live in World.phaseName().

Domain events are emitted at central mutation points: placement, eating, decay, effect apply/remove, disease infect/cure, damage/death/birth, fight hit/loss/end, ant spawn/grab/carry/death, weather changes, and rain item drops. Logs/audio still use direct calls where they already existed; do not add duplicate log or sound side effects when subscribing to these events.

Ant behavior remains intentionally conservative. ANT_EXTENSION_HOOKS names future ecology slots for nest hunger, nest growth, queen reproduction, worker lifecycle, carrying success, and territorial behavior, but this pass does not rebalance those mechanics.

Spatial/performance rules

Use World.nearby* helpers rather than full-array scans in hot paths. Terrain cache uses dirty/version flags; do not reintroduce every-frame full terrain hashing. Performance degradation should be centralized in performance_manager.js.

Family tree rendering is intentionally asynchronous and cached. ui_family_async.js chunks component discovery with requestIdleCallback when available; ui_family_render.js hydrates cached HTML, keeps archive dirty/version state, and exposes validateFamilyTree() plus familyTreeDiagnostics() for browser-console checks.

Basic ActionSpec migration

Version 15.24.33 keeps low-risk need actions, social/fear/combat/mate/birth actions, and sunbath registered through ActionSpec factories. The former configureTarinaiNeedActions late-binding bridge has been removed; the existing sunbath subsystem remains as the body-level timer implementation called by the ActionSpec.

Runtime diagnostics

World.runtimeDiagnostics() exposes spatial rebuild counters, draw-list status, item bucket counts, and behavior counts. ?debug=1 renders these values in the existing debug overlay for manual browser regression checks.

Social balance guards

Version 15.24.33 adds explicit guardrails around combat-heavy social behavior. Normal conflict must be dominant over bond/mate/family pressure before fight_rival can start, and World.startFight() / startConflict() / startForcedFight() use pair-level cooldowns plus already-fighting checks to prevent burst re-entry. Fight mochi remains a strong forced exception, but ordinary proximity conflict is intentionally lower than mate/friend pressure.

Pre-save runtime polish

Version 15.24.33 keeps item type buckets and item id lookup as runtime caches owned by World.updateItemCounts(). Runtime item additions should go through World.addItem(item, reason) when practical so spatial, terrain, and item-bucket invalidation stay synchronized. Save migration is still intentionally deferred until this runtime shape has been browser-observed.