# GroveEngine - Supplementary Design Document **Date créé** : 24 novembre 2025 **Auteur** : Alexis (avec Claude Code) **Status** : Architecture Planning --- ## CONTEXTE **GroveEngine** est un moteur de jeu multi-projets conçu pour être : - **Data-driven** : Config/text-based pour tout ce qui est modifiable - **AI-friendly** : LLM peut créer/modifier assets sans toucher au code C++ - **Multi-backend rendering** : Support Vulkan/DX12/Metal/OpenGL via bgfx - **Solide & réutilisable** : Foundation pour plusieurs projets **État actuel** : - ✅ Coeur engine done (mode debug) - ❌ Pas de rendering - ❌ Pas de framework 2D/UI --- ## PROJETS BASÉS SUR GROVEENGINE 1. **Pokrovsk: Iron Line** (survival management, train builder) 2. **AISSIA** (concepts via SecondVoice/YT-DL) 3. **Troisième projet** : À définir **Objectif** : Un seul moteur, plusieurs jeux, maintenance centralisée. --- ## STACK TECHNIQUE ### Rendering - **bgfx** : Abstraction multi-backend (Vulkan/DX12/Metal/OpenGL) - Multi-platform par design - Performant pour 2D (batching, sprites) - Mature (utilisé par Defold engine) - Dev : Branimir Karadzic (ex-Frostbite EA) - **SDL2** : Windowing + input - Cross-platform - Léger, bien supporté - **stb_image** : Texture loading - Single-header, simple ### Serialization/Config - **yaml-cpp** : YAML parsing - Entities definitions - Missions, events, dialogues - **nlohmann/json** : JSON parsing - UI layouts - Save files - Asset manifests (alternative) - **TOML++** : Config files - Settings, constants - Game balance values ### UI - **ImGui** : Debug/tools UI (dev only) - Immediate mode - Parfait pour tools - **Custom UI system** (bgfx-based) : In-game UI - JSON-driven layouts - Rendering via bgfx - Themeable ### Scripting (optionnel) - **Lua** : Si besoin de scripting pour game logic - **Alternative** : Config-only (YAML events + state machines) - Plus simple - Assez pour beaucoup de cas --- ## ARCHITECTURE AI-FRIENDLY **Principe** : LLM peut créer/modifier game content sans toucher au code C++. ### 1. Entity System (Data-Driven) **Structure** : ``` entities/ ├── wagons/ │ ├── wagon_basic.yaml │ ├── wagon_armored.yaml │ └── wagon_workshop.yaml ├── drones/ │ ├── mavic_reco.yaml │ └── fpv_strike.yaml └── humans/ └── commandant_template.yaml ``` **Exemple : entities/wagons/wagon_basic.yaml** ```yaml entity: wagon_basic components: - type: visual sprite: wagon_base.png size: [20, 6] # Grille interne - type: balance weight: 5.0 center_of_mass: [10, 3] dampeners: 0 # Upgrade level - type: slots grid: [20, 6] layers: [high, low] specialization: null # production, logistic, habitation, military - type: health hp_max: 100 armor: 10 ``` **LLM peut** : Créer nouveaux wagons, tweaker stats, ajouter composants. --- ### 2. UI Layouts (Declarative JSON) **Structure** : ``` ui/ ├── screens/ │ ├── train_builder.json │ ├── mission_briefing.json │ └── campaign_map.json └── widgets/ ├── balance_gauge.json └── resource_panel.json ``` **Exemple : ui/screens/train_builder.json** ```json { "screen": "train_builder", "elements": [ { "type": "panel", "id": "wagon_view", "rect": [0, 0, 800, 600], "background": "#2a2a2a", "children": [ { "type": "sprite", "id": "wagon_display", "anchor": "center" } ] }, { "type": "gauge", "id": "balance_lateral", "rect": [820, 20, 160, 40], "label": "Balance G/D", "min": -10, "max": 10, "value_binding": "wagon.balance.lateral", "color_good": "#00ff00", "color_warning": "#ffaa00", "color_bad": "#ff0000" }, { "type": "text", "id": "wagon_name", "rect": [820, 80, 160, 30], "text_binding": "wagon.name", "font": "main_ui", "size": 18, "color": "#ffffff" } ] } ``` **LLM peut** : Créer UI screens, repositionner éléments, modifier styles, créer layouts. --- ### 3. Game Logic (Config-Driven Events) **Structure** : ``` content/ ├── missions/ │ ├── 2022_early/ │ │ ├── scavenge_kyiv.yaml │ │ └── rescue_civilians.yaml │ └── 2025_late/ │ └── drone_intercept.yaml ├── events/ │ ├── random_events.yaml │ └── story_events.yaml └── dialogues/ └── commandants/ ├── sergei.yaml └── oksana.yaml ``` **Exemple : missions/2022_early/scavenge_kyiv.yaml** ```yaml mission: id: scavenge_kyiv_outskirts name: "Colonne russe détruite - Périphérie Kyiv" year: 2022 period: early difficulty: easy briefing: text: | Colonne blindée russe détruite à 2km au nord. Reconnaissance indique 8-10 véhicules abandonnés. Opposition minimale attendue. intel: - "Matériel récent, peu endommagé" - "Zone relativement sécurisée" - "Temps limité avant arrivée autres scavengers" rewards: metal: [50, 100] electronics: [20, 40] components_military: [5, 15] fame: 10 risks: - type: ambush probability: 0.1 - type: mines probability: 0.15 events: - trigger: mission_start text: "Votre équipe approche la colonne détruite..." choices: - id: approach_cautious text: "Approche prudente (sweep mines)" time_cost: 2h risk_modifier: -0.5 - id: rush text: "Rush rapide (grab & go)" time_cost: 30min risk_modifier: +0.8 reward_modifier: 1.2 - trigger: loot_phase condition: "approach_cautious" text: "Temps de fouiller méthodiquement..." outcomes: - probability: 0.7 result: success rewards_modifier: 1.0 - probability: 0.3 result: partial rewards_modifier: 0.6 ``` **LLM peut** : Créer missions, events, dialogues, choix, outcomes. --- ### 4. Asset Pipeline (Text Metadata) **Structure** : ``` assets/ ├── sprites/ │ ├── wagons.manifest │ ├── drones.manifest │ └── ui.manifest ├── textures/ │ └── (PNG files) └── fonts/ └── fonts.manifest ``` **Exemple : assets/sprites/wagons.manifest (TOML)** ```toml [wagon_base] file = "textures/wagon_base.png" size = [400, 120] pivot = [200, 60] tags = ["wagon", "basic"] [wagon_armored] file = "textures/wagon_armored.png" size = [400, 120] pivot = [200, 60] weight_modifier = 1.5 tags = ["wagon", "armored", "heavy"] [wagon_workshop] file = "textures/wagon_workshop.png" size = [400, 140] # Plus haut pivot = [200, 70] specialization = "production" tags = ["wagon", "specialized"] ``` **LLM peut** : Définir assets, metadata, tags, modifiers. --- ## ARCHITECTURE ENGINE ### Core Systems **1. Entity Component System (ECS)** ```cpp class Entity { EntityID id; std::vector components; }; class Component { virtual void Update(float dt) = 0; virtual void Serialize(YAML::Node& node) = 0; virtual void Deserialize(const YAML::Node& node) = 0; }; // Exemples components class VisualComponent : public Component { ... } class BalanceComponent : public Component { ... } class SlotsComponent : public Component { ... } ``` **2. Asset Manager** ```cpp class AssetManager { // Textures std::map textures; // Manifests (metadata) std::map metadata; // Fonts std::map fonts; void LoadManifest(const std::string& path); bgfx::TextureHandle GetTexture(const std::string& id); }; ``` **3. Config System** ```cpp class ConfigManager { YAML::Node LoadYAML(const std::string& path); nlohmann::json LoadJSON(const std::string& path); Entity* CreateEntityFromYAML(const std::string& entity_id); UIScreen* CreateUIFromJSON(const std::string& screen_id); }; ``` **4. Rendering 2D (bgfx-based)** ```cpp class Renderer2D { bgfx::ProgramHandle sprite_shader; // Sprite batching pour performance struct SpriteBatch { std::vector vertices; bgfx::TextureHandle texture; }; void DrawSprite(const Sprite& sprite); void DrawRect(const Rect& rect, Color color); void DrawText(const std::string& text, Font font, Vec2 pos); void Flush(); // Submit batched draws }; ``` **5. UI System (JSON-driven)** ```cpp class UIManager { std::map screens; UIScreen* LoadScreen(const std::string& screen_json); void Update(float dt); void Render(Renderer2D& renderer); // Data binding void BindValue(const std::string& path, float* value); void BindText(const std::string& path, std::string* text); }; class UIElement { std::string id; Rect rect; virtual void Render(Renderer2D& renderer) = 0; virtual void Update(float dt) = 0; }; // Concrete elements class UIPanel : public UIElement { ... } class UIGauge : public UIElement { ... } class UIText : public UIElement { ... } class UISprite : public UIElement { ... } ``` --- ## RENDERING 2D AVEC BGFX ### Concept de base **bgfx ne fait PAS de 2D directement** → Tu construis la couche 2D par-dessus. ### Primitive : Quad (pour sprites) ```cpp struct SpriteVertex { float x, y, z; // Position float u, v; // UV coords (texture) uint32_t color; // Tint color (ABGR) }; // Vertex layout bgfx bgfx::VertexLayout sprite_layout; sprite_layout.begin() .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float) .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true) .end(); ``` ### Sprite Rendering ```cpp void Renderer2D::DrawSprite(const Sprite& sprite) { // 1. Batch sprite (grouper par texture) GetOrCreateBatch(sprite.texture).AddQuad(sprite); } void Renderer2D::Flush() { // 2. Pour chaque batch, submit draw call for (auto& batch : batches) { bgfx::setTexture(0, sampler, batch.texture); bgfx::setVertexBuffer(0, batch.vertex_buffer); bgfx::setIndexBuffer(batch.index_buffer); bgfx::setState(BGFX_STATE_DEFAULT); bgfx::submit(view_id, sprite_shader); } batches.clear(); } ``` ### Camera 2D (Orthographic) ```cpp class Camera2D { Vec2 position; float zoom; Mat4 GetViewMatrix() const { return Mat4::Translation(-position.x, -position.y, 0); } Mat4 GetProjectionMatrix(int width, int height) const { float halfW = (width / zoom) * 0.5f; float halfH = (height / zoom) * 0.5f; return Mat4::Ortho(-halfW, halfW, -halfH, halfH, -1, 1); } }; // Usage bgfx::setViewTransform(view_id, camera.GetViewMatrix().data, camera.GetProjectionMatrix(screenW, screenH).data ); ``` --- ## PLAN DE DÉVELOPPEMENT ### Phase 1 : Core Engine (3-4 semaines) **Semaine 1-2 : Setup bgfx + SDL2** - [ ] Intégrer bgfx, bx, bimg dans projet (git submodules) - [ ] Build bgfx pour platform cible - [ ] Window SDL2 + init bgfx - [ ] Clear screen avec couleur - [ ] Input basique (keyboard, mouse) **Semaine 3 : Rendering 2D basique** - [ ] Vertex layout sprites - [ ] Shader simple (texture + color tint) - [ ] Afficher 1 sprite (quad texturé) - [ ] Camera 2D orthographique **Semaine 4 : Asset Pipeline** - [ ] Texture loading (stb_image) - [ ] AssetManager basique - [ ] Manifest TOML (assets metadata) - [ ] Load sprite from manifest --- ### Phase 2 : Framework 2D (2-3 semaines) **Semaine 5 : Sprite System** - [ ] Sprite batching (group by texture) - [ ] DrawSprite API - [ ] DrawRect (colored quads) - [ ] Transform system (position, rotation, scale) **Semaine 6 : UI Primitives** - [ ] Text rendering (stb_truetype ou FreeType) - [ ] Font loading via manifest - [ ] DrawText API - [ ] UI elements basiques (Panel, Text, Sprite) **Semaine 7 : Input & Interaction** - [ ] Mouse picking (screen → world coords) - [ ] Drag & drop basique - [ ] Button clicks - [ ] Input manager --- ### Phase 3 : Entity System (2-3 semaines) **Semaine 8 : ECS Core** - [ ] Entity class - [ ] Component base class - [ ] Entity manager (create, destroy, query) - [ ] YAML serialization/deserialization **Semaine 9 : Components Library** - [ ] VisualComponent (sprite rendering) - [ ] TransformComponent (position, rotation) - [ ] BalanceComponent (pour Pokrovsk wagons) - [ ] SlotsComponent (grille placement) **Semaine 10 : Config Integration** - [ ] Load entity from YAML - [ ] Entity templates system - [ ] Component factory (deserialize components) --- ### Phase 4 : UI System (2-3 semaines) **Semaine 11 : UI Framework** - [ ] UIElement base class - [ ] UIManager (screen stack) - [ ] Layout system (anchors, rects) - [ ] JSON UI loading **Semaine 12 : UI Widgets** - [ ] UIPanel - [ ] UIText (with data binding) - [ ] UIGauge (progress bar, balance gauge) - [ ] UIButton **Semaine 13 : Advanced UI** - [ ] Data binding system (link UI ↔ game data) - [ ] Events (onClick, onHover) - [ ] Theming (colors, fonts from config) --- ### Phase 5 : Validation Pokrovsk (2-3 semaines) **Semaine 14 : Wagon Entity** - [ ] Wagon YAML definition - [ ] Instantiate wagon from config - [ ] Render wagon sprite (double slice) - [ ] Display balance gauges (UI) **Semaine 15 : Train Builder UI** - [ ] Train builder screen (JSON) - [ ] Grid overlay (slots) - [ ] Drag & drop elements (atelier, stockage, dortoir) - [ ] Real-time balance calculation **Semaine 16 : Polish & Validation** - [ ] Balance visualization (wagon tilts if unbalanced) - [ ] Element placement constraints - [ ] Save/load train configuration - [ ] Prototype jouable = validation complète --- **TOTAL : ~10-16 semaines pour moteur complet + prototype Pokrovsk** --- ## AVANTAGES POUR LLM ### Ce que LLM peut créer/modifier sans code C++ : **Entities** - ✅ Wagons (YAML) : stats, composants, visuel - ✅ Drones (YAML) : types, capacités - ✅ Commandants (YAML) : skills, personnalité - ✅ Missions (YAML) : events, choix, rewards **UI** - ✅ Screens (JSON) : layouts, elements - ✅ Widgets (JSON) : gauges, panels, text - ✅ Themes (JSON) : colors, fonts, styles **Content** - ✅ Dialogues (YAML) - ✅ Events (YAML) - ✅ Story beats (YAML) - ✅ Balance values (TOML) **Assets** - ✅ Manifests (TOML) : sprites metadata - ✅ Tags, categories, filters - ✅ Asset relationships ### Workflow LLM **Exemple : "Créer un nouveau wagon blindé lourd"** 1. LLM crée `entities/wagons/wagon_heavy_armored.yaml` 2. LLM met à jour `assets/sprites/wagons.manifest` (nouveau sprite) 3. LLM peut tester en modifiant une mission pour donner ce wagon 4. **Aucun code C++ touché** --- ## QUESTIONS OUVERTES ### Architecture 1. **Scripting Lua ou config-only ?** - Lua = plus flexible pour game logic - Config = plus simple, assez pour events/missions - **Décision** : À trancher selon complexité game logic 2. **Save system format ?** - JSON (human-readable, LLM-friendly) - Binaire (compact, rapide) - **Recommandation** : JSON pour dev, option binaire pour release 3. **Networking futur ?** - Pokrovsk = solo only - Autres projets ? - **Impact** : Architecture ECS doit supporter network sync ou pas ### Performance 4. **Sprite batching strategy ?** - Batch par texture (standard) - Batch par layer (z-order) - **Décision** : Tester performance avec prototype 5. **Entity pooling ?** - Object pooling pour éviter alloc/dealloc - Critical pour drones (100+ entities) - **Recommandation** : Oui, implement dès Phase 3 ### Tooling 6. **Level editor ?** - ImGui-based editor in-engine - Externe (web-based ?) - **Recommandation** : ImGui in-engine = plus rapide 7. **Asset hot-reload ?** - Reload YAML/JSON/textures sans restart - Crucial pour iteration rapide - **Recommandation** : Oui, implement Phase 2-3 --- ## DÉPENDANCES EXTERNES ### Obligatoires - **bgfx** : Rendering (https://github.com/bkaradzic/bgfx) - **bx** : Base library pour bgfx (https://github.com/bkaradzic/bx) - **bimg** : Image loading pour bgfx (https://github.com/bkaradzic/bimg) - **SDL2** : Windowing + input (https://www.libsdl.org/) - **yaml-cpp** : YAML parsing (https://github.com/jbeder/yaml-cpp) - **nlohmann/json** : JSON parsing (https://github.com/nlohmann/json) - **stb_image** : Image loading (https://github.com/nothings/stb) ### Optionnelles - **TOML++** : TOML parsing (https://github.com/marzer/tomlplusplus) - **ImGui** : Debug UI (https://github.com/ocornut/imgui) - **Lua** : Scripting (https://www.lua.org/) - **stb_truetype** : Font rendering (https://github.com/nothings/stb) - **FreeType** : Alternative font rendering (https://freetype.org/) --- ## RISQUES & MITIGATION | Risque | Impact | Probabilité | Mitigation | |--------|--------|-------------|------------| | bgfx trop complexe | HAUT | MOYEN | Exemples officiels, communauté active | | Scope creep framework | HAUT | HAUT | Lock features après Phase 4, focus prototype | | Performance 2D insuffisante | MOYEN | FAIBLE | Batching + profiling dès Phase 2 | | Config system trop rigide | MOYEN | MOYEN | Itérer avec prototype Pokrovsk | | LLM-generated content bugs | MOYEN | MOYEN | Validation schema (JSON schema, YAML schema) | | Timeline trop optimiste | HAUT | MOYEN | Buffers 20% par phase | --- ## RÉFÉRENCES ### bgfx - Repo officiel : https://github.com/bkaradzic/bgfx - Documentation : https://bkaradzic.github.io/bgfx/ - Exemples : https://github.com/bkaradzic/bgfx/tree/master/examples ### Architecture ECS - "Overwatch Gameplay Architecture" (GDC Talk) - "Data-Oriented Design" (Richard Fabian) ### 2D Rendering bgfx - bgfx example-26 (vectordisplay) - NanoVG-bgfx (https://github.com/memononen/nanovg) --- ## NEXT STEPS 1. **Setup projet** : Créer repo GroveEngine, structure folders 2. **Intégrer bgfx** : Submodules + build 3. **Hello Triangle** : Première fenêtre + rendering 4. **Suivre plan Phase 1** : 4 semaines pour core engine --- **Document Version** : 1.0 **Status** : Architecture Design **Owner** : Alexis **Related** : `Projects/CONCEPT/pokrovsk_iron_line_v2.md`