From 0654db6a810c8ba6394c29d92a6608c363efc035 Mon Sep 17 00:00:00 2001 From: StillHammer Date: Wed, 26 Nov 2025 12:02:43 +0800 Subject: [PATCH] Add project documentation for morning setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Confluent: Conlang skeleton (phonology + proto-roots) - GroveEngine RenderModule: Window + 2D UI rendering architecture - Aissia: AI subsystem with LLM API calls + async processing đŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- Projects/WIP/AISSIA.md | 235 +++++++++- Projects/WIP/Confluent.md | 76 +++ Projects/WIP/GroveEngine_RenderModule.md | 561 +++++++++++++++++++++++ 3 files changed, 871 insertions(+), 1 deletion(-) create mode 100644 Projects/WIP/Confluent.md create mode 100644 Projects/WIP/GroveEngine_RenderModule.md diff --git a/Projects/WIP/AISSIA.md b/Projects/WIP/AISSIA.md index c48abbd..c4a7220 100644 --- a/Projects/WIP/AISSIA.md +++ b/Projects/WIP/AISSIA.md @@ -79,6 +79,233 @@ Projets/ --- +## AI Subsystem Architecture + +### API Call Management + +**LLM Provider Abstraction** +```cpp +class ILLMProvider { +public: + virtual ~ILLMProvider() = default; + + struct Message { + std::string role; // "user", "assistant", "system" + std::string content; + }; + + struct CompletionRequest { + std::vector messages; + float temperature = 0.7f; + int max_tokens = 1000; + std::string model; + }; + + struct CompletionResponse { + std::string content; + int tokens_used; + float cost_usd; + bool success; + std::string error; + }; + + virtual CompletionResponse Complete(const CompletionRequest& req) = 0; +}; +``` + +**Implementations** +```cpp +// Claude API (Anthropic) +class ClaudeProvider : public ILLMProvider { + std::string api_key; + std::string endpoint = "https://api.anthropic.com/v1/messages"; + + CompletionResponse Complete(const CompletionRequest& req) override; +}; + +// GPT API (OpenAI) +class GPTProvider : public ILLMProvider { + std::string api_key; + std::string endpoint = "https://api.openai.com/v1/chat/completions"; + + CompletionResponse Complete(const CompletionRequest& req) override; +}; + +// Local LLM (Llama via llama.cpp server) +class LocalLLMProvider : public ILLMProvider { + std::string endpoint = "http://localhost:8080/v1/chat/completions"; + + CompletionResponse Complete(const CompletionRequest& req) override; +}; +``` + +### AISubsystem Module + +```cpp +class AISubsystem : public grove::IModule { +public: + void initialize(const IDataNode& config, IIO* io) override; + void update(float dt) override; + void shutdown() override; + + // High-level API + std::string AskQuestion(const std::string& question, const std::string& context); + std::string GenerateResponse(const std::vector& conversation); + + // Context management + void SetSystemPrompt(const std::string& prompt); + void AddContext(const std::string& key, const std::string& value); + void ClearContext(); + +private: + std::unique_ptr provider; + std::string system_prompt; + std::map context_data; + + // Request queue (async processing) + std::queue pending_requests; + std::thread worker_thread; +}; +``` + +### HTTP Client (API Calls) + +**Using libcurl (C++ wrapper)** +```cpp +class HTTPClient { +public: + struct Request { + std::string url; + std::string method; // GET, POST + std::map headers; + std::string body; + }; + + struct Response { + int status_code; + std::string body; + std::map headers; + }; + + Response Send(const Request& req); + +private: + CURL* curl; +}; + +// Usage pour LLM API +HTTPClient client; +HTTPClient::Request req; +req.url = "https://api.anthropic.com/v1/messages"; +req.method = "POST"; +req.headers["x-api-key"] = api_key; +req.headers["Content-Type"] = "application/json"; +req.body = R"({ + "model": "claude-3-5-sonnet-20241022", + "messages": [{"role": "user", "content": "Hello!"}], + "max_tokens": 1024 +})"; + +auto response = client.Send(req); +``` + +### Async Processing (Non-blocking) + +```cpp +void AISubsystem::update(float dt) { + // Process pending requests asynchronously + if (!pending_requests.empty() && !worker_thread.joinable()) { + auto request = pending_requests.front(); + pending_requests.pop(); + + worker_thread = std::thread([this, request]() { + auto response = provider->Complete(request); + + // Send response via IIO to other modules + io->SendMessage("ai_response", response.content); + }); + } + + // Cleanup finished threads + if (worker_thread.joinable()) { + worker_thread.join(); + } +} +``` + +### Configuration + +**Config file : `aissia_ai_config.json`** +```json +{ + "ai_subsystem": { + "provider": "claude", + "api_key_env": "ANTHROPIC_API_KEY", + "model": "claude-3-5-sonnet-20241022", + "default_temperature": 0.7, + "max_tokens": 1000, + "system_prompt": "You are AISSIA, an AI assistant helping manage hyperfocus and time management.", + "timeout_seconds": 30, + "retry_attempts": 3 + }, + "providers": { + "claude": { + "endpoint": "https://api.anthropic.com/v1/messages", + "cost_per_1k_input": 0.003, + "cost_per_1k_output": 0.015 + }, + "gpt": { + "endpoint": "https://api.openai.com/v1/chat/completions", + "cost_per_1k_input": 0.00015, + "cost_per_1k_output": 0.0006 + }, + "local": { + "endpoint": "http://localhost:8080/v1/chat/completions", + "cost_per_1k_input": 0.0, + "cost_per_1k_output": 0.0 + } + } +} +``` + +### TTS/STT (Bonus) + +**Text-to-Speech Options** +```cpp +class ITTSProvider { +public: + virtual void Speak(const std::string& text) = 0; +}; + +// Windows SAPI (already documented in daily check system) +class WindowsSAPIProvider : public ITTSProvider { + void Speak(const std::string& text) override { + // Use SAPI COM interface + // See: anki_tingting/CLAUDE.md for implementation + } +}; + +// ElevenLabs API (cloud, high quality) +class ElevenLabsProvider : public ITTSProvider { + void Speak(const std::string& text) override; +}; +``` + +**Speech-to-Text Options** +```cpp +class ISTTProvider { +public: + virtual std::string Transcribe(const std::vector& audio_data) = 0; +}; + +// Whisper API (OpenAI) +class WhisperProvider : public ISTTProvider { + std::string Transcribe(const std::vector& audio_data) override; +}; +``` + +--- + ## Modules AISSIA PrĂ©vus Architecture modulaire GroveEngine : @@ -288,9 +515,15 @@ GetWindowThreadProcessId(hwnd, &processId); **ImmĂ©diat** : 1. ✅ Build test GroveEngine (vĂ©rifier que ça compile) 2. ⏳ CrĂ©er `aissia-core.exe` (DebugEngine wrapper) -3. ⏳ DĂ©velopper premier module (MonitoringModule simple) +3. ⏳ DĂ©velopper AISubsystem (LLM API calls + management) 4. ⏳ Valider hot-reload 0.4ms avec module AISSIA +**Base Running Requirements** : +- ✅ GroveEngine integrated +- ⏳ LLM API subsystem (Claude/GPT calls) +- ⏳ AI subsystem management (context, prompts, responses) +- 🎁 Bonus: TTS/STT APIs (optionnel) + **Questions bloquantes** : - LLM choice pour AIAssistantModule ? - Niveau d'intervention acceptable (kill process ou juste notifs) ? diff --git a/Projects/WIP/Confluent.md b/Projects/WIP/Confluent.md new file mode 100644 index 0000000..a10626e --- /dev/null +++ b/Projects/WIP/Confluent.md @@ -0,0 +1,76 @@ +# Confluent - Langue Construite + +**Statut** : WIP +**Type** : Conlang (langue construite) +**Contexte** : LiĂ© au projet civjdr (Civilisation de la Confluence) +**DerniĂšre mise Ă  jour** : 26 novembre 2025 + +--- + +## Vue d'ensemble + +Langue construite pour la Civilisation de la Confluence (civjdr). + +**À complĂ©ter** : Informations dĂ©taillĂ©es depuis laptop + +--- + +## Phonologie & PhonĂ©tique + +### Inventaire PhonĂ©mique + +**À complĂ©ter** + +#### Consonnes + +[Tableau des consonnes Ă  ajouter] + +#### Voyelles + +[Tableau des voyelles Ă  ajouter] + +### RĂšgles Phonotactiques + +**À complĂ©ter** + +- Structure syllabique : +- Contraintes : +- Assimilations : +- Stress/Accent : + +--- + +## Racines Proto-Confluent + +### SystĂšme de Racines + +**À complĂ©ter** + +### Racines Fondamentales + +**À complĂ©ter** + +| Racine | Sens | DĂ©rivations | Notes | +|--------|------|-------------|-------| +| | | | | + +### Évolution Diachronique + +**À complĂ©ter** + +- Proto-Confluent → Confluent moderne +- Changements sonores majeurs +- Innovations grammaticales + +--- + +## Notes de DĂ©veloppement + +**26 novembre 2025** : Squelette créé, donnĂ©es dĂ©taillĂ©es Ă  transfĂ©rer depuis laptop + +--- + +## Ressources + +- Lien civjdr : `Projects/CONSTANT/civjdr.md` +- [Autres ressources Ă  ajouter] diff --git a/Projects/WIP/GroveEngine_RenderModule.md b/Projects/WIP/GroveEngine_RenderModule.md new file mode 100644 index 0000000..722d692 --- /dev/null +++ b/Projects/WIP/GroveEngine_RenderModule.md @@ -0,0 +1,561 @@ +# GroveEngine - RenderModule (Framework Module) + +**Type** : Framework Module (base avancĂ©e) +**Stack** : bgfx + SDL2 +**Objectif** : Window + UI 2D element rendering +**DerniĂšre mise Ă  jour** : 26 novembre 2025 + +--- + +## Vue d'ensemble + +Module framework pour GroveEngine fournissant les capacitĂ©s de rendu 2D de base : +- **Window management** via SDL2 +- **Rendering 2D** via bgfx (multi-backend : Vulkan/DX12/Metal/OpenGL) +- **UI element rendering** (primitives 2D) + +**Base avancĂ©e** = IntĂ©gration complĂšte dans le GroveEngine + capacitĂ©s rendering fonctionnelles + +--- + +## Architecture Module + +### Integration GroveEngine + +```cpp +class RenderModule : public grove::IModule { +public: + // IModule interface + void initialize(const IDataNode& config, IIO* io) override; + void update(float dt) override; + void shutdown() override; + + // Rendering API + void BeginFrame(); + void EndFrame(); + + // 2D Primitives + void DrawRect(const Rect& rect, Color color); + void DrawSprite(const Sprite& sprite); + void DrawText(const std::string& text, Font font, Vec2 pos); + +private: + SDL_Window* window; + bgfx::ViewId main_view; + Renderer2D renderer; +}; +``` + +### Composants ClĂ©s + +**1. Window Management (SDL2)** +```cpp +struct WindowConfig { + int width; + int height; + std::string title; + bool fullscreen; + bool vsync; +}; + +// CrĂ©ation window SDL2 +window = SDL_CreateWindow( + config.title.c_str(), + SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, + config.width, + config.height, + SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE +); +``` + +**2. bgfx Initialization** +```cpp +bgfx::Init init; +init.type = bgfx::RendererType::Count; // Auto-detect +init.resolution.width = width; +init.resolution.height = height; +init.resolution.reset = BGFX_RESET_VSYNC; + +// Utilise window SDL2 +SDL_SysWMinfo wmi; +SDL_VERSION(&wmi.version); +SDL_GetWindowWMInfo(window, &wmi); + +#if BX_PLATFORM_WINDOWS + init.platformData.nwh = wmi.info.win.window; +#elif BX_PLATFORM_LINUX + init.platformData.ndt = wmi.info.x11.display; + init.platformData.nwh = (void*)(uintptr_t)wmi.info.x11.window; +#endif + +bgfx::init(init); +``` + +**3. Renderer2D (Primitives)** +```cpp +class Renderer2D { +public: + void DrawRect(const Rect& rect, Color color); + void DrawSprite(const Sprite& sprite); + void Flush(); // Submit batched draws + +private: + bgfx::ProgramHandle sprite_shader; + bgfx::ProgramHandle color_shader; + + struct SpriteBatch { + std::vector vertices; + bgfx::TextureHandle texture; + }; + + std::vector batches; +}; +``` + +--- + +## Rendering Pipeline + +### Frame Structure + +```cpp +void RenderModule::update(float dt) { + BeginFrame(); + + // Rendering commands + DrawRect({100, 100, 200, 150}, Color::Red()); + DrawSprite(test_sprite); + DrawText("Hello GroveEngine", main_font, {50, 50}); + + EndFrame(); +} + +void RenderModule::BeginFrame() { + bgfx::touch(main_view); + bgfx::setViewClear(main_view, + BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, + 0x303030ff, 1.0f, 0); +} + +void RenderModule::EndFrame() { + renderer.Flush(); // Submit batched draws + bgfx::frame(); // Advance frame +} +``` + +### Vertex Formats + +**Sprite Vertex (textured quad)** +```cpp +struct SpriteVertex { + float x, y, z; // Position + float u, v; // UV coords + uint32_t color; // Tint (ABGR) +}; + +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(); +``` + +**Color Vertex (solid color quad)** +```cpp +struct ColorVertex { + float x, y, z; + uint32_t color; +}; + +bgfx::VertexLayout color_layout; +color_layout.begin() + .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) + .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true) + .end(); +``` + +--- + +## Shaders + +### Sprite Shader (Vertex) + +```glsl +// vs_sprite.sc +$input a_position, a_texcoord0, a_color0 +$output v_texcoord0, v_color0 + +#include + +void main() { + gl_Position = mul(u_modelViewProj, vec4(a_position, 1.0)); + v_texcoord0 = a_texcoord0; + v_color0 = a_color0; +} +``` + +### Sprite Shader (Fragment) + +```glsl +// fs_sprite.sc +$input v_texcoord0, v_color0 + +#include + +SAMPLER2D(s_texture, 0); + +void main() { + vec4 texColor = texture2D(s_texture, v_texcoord0); + gl_FragColor = texColor * v_color0; +} +``` + +**Compilation** : +```bash +shaderc -f vs_sprite.sc -o vs_sprite.bin --type vertex --platform linux -p 120 +shaderc -f fs_sprite.sc -o fs_sprite.bin --type fragment --platform linux -p 120 +``` + +--- + +## Camera 2D + +### Orthographic Projection + +```cpp +class Camera2D { +public: + Vec2 position; + float zoom = 1.0f; + + 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); + } +}; + +// Setup view transform +Mat4 view = camera.GetViewMatrix(); +Mat4 proj = camera.GetProjectionMatrix(screenW, screenH); +bgfx::setViewTransform(main_view, view.data, proj.data); +``` + +--- + +## UI Element Rendering + +### DrawRect Implementation + +```cpp +void Renderer2D::DrawRect(const Rect& rect, Color color) { + ColorVertex vertices[4] = { + {rect.x, rect.y, 0, color.abgr()}, + {rect.x + rect.w, rect.y, 0, color.abgr()}, + {rect.x + rect.w, rect.y + rect.h, 0, color.abgr()}, + {rect.x, rect.y + rect.h, 0, color.abgr()} + }; + + uint16_t indices[6] = {0, 1, 2, 0, 2, 3}; + + bgfx::TransientVertexBuffer tvb; + bgfx::TransientIndexBuffer tib; + + bgfx::allocTransientVertexBuffer(&tvb, 4, color_layout); + bgfx::allocTransientIndexBuffer(&tib, 6); + + memcpy(tvb.data, vertices, sizeof(vertices)); + memcpy(tib.data, indices, sizeof(indices)); + + bgfx::setVertexBuffer(0, &tvb); + bgfx::setIndexBuffer(&tib); + bgfx::setState(BGFX_STATE_DEFAULT); + bgfx::submit(main_view, color_shader); +} +``` + +### DrawSprite Implementation (Batched) + +```cpp +void Renderer2D::DrawSprite(const Sprite& sprite) { + // Find or create batch for this texture + SpriteBatch* batch = GetBatchForTexture(sprite.texture); + + // Add quad to batch + float x0 = sprite.pos.x; + float y0 = sprite.pos.y; + float x1 = x0 + sprite.size.x; + float y1 = y0 + sprite.size.y; + + uint32_t color = sprite.tint.abgr(); + + batch->vertices.push_back({x0, y0, 0, 0, 0, color}); + batch->vertices.push_back({x1, y0, 0, 1, 0, color}); + batch->vertices.push_back({x1, y1, 0, 1, 1, color}); + batch->vertices.push_back({x0, y1, 0, 0, 1, color}); +} + +void Renderer2D::Flush() { + for (auto& batch : batches) { + size_t quad_count = batch.vertices.size() / 4; + + // Generate indices (0,1,2, 0,2,3 per quad) + std::vector indices; + for (size_t i = 0; i < quad_count; ++i) { + uint16_t base = i * 4; + indices.push_back(base + 0); + indices.push_back(base + 1); + indices.push_back(base + 2); + indices.push_back(base + 0); + indices.push_back(base + 2); + indices.push_back(base + 3); + } + + // Submit draw call + bgfx::TransientVertexBuffer tvb; + bgfx::TransientIndexBuffer tib; + + bgfx::allocTransientVertexBuffer(&tvb, batch.vertices.size(), sprite_layout); + bgfx::allocTransientIndexBuffer(&tib, indices.size()); + + memcpy(tvb.data, batch.vertices.data(), batch.vertices.size() * sizeof(SpriteVertex)); + memcpy(tib.data, indices.data(), indices.size() * sizeof(uint16_t)); + + bgfx::setTexture(0, sampler, batch.texture); + bgfx::setVertexBuffer(0, &tvb); + bgfx::setIndexBuffer(&tib); + bgfx::setState(BGFX_STATE_DEFAULT); + bgfx::submit(main_view, sprite_shader); + } + + batches.clear(); +} +``` + +--- + +## Configuration Module + +### Config File (JSON) + +```json +{ + "module": "RenderModule", + "window": { + "width": 1280, + "height": 720, + "title": "GroveEngine - RenderModule Test", + "fullscreen": false, + "vsync": true + }, + "rendering": { + "clear_color": "#303030", + "main_view_id": 0 + } +} +``` + +### Loading Config + +```cpp +void RenderModule::initialize(const IDataNode& config, IIO* io) { + WindowConfig window_config; + window_config.width = config.get("window.width", 1280); + window_config.height = config.get("window.height", 720); + window_config.title = config.get("window.title", "GroveEngine"); + window_config.vsync = config.get("window.vsync", true); + + InitializeWindow(window_config); + InitializeBgfx(window_config); + InitializeRenderer(); +} +``` + +--- + +## Roadmap DĂ©veloppement + +### Phase 1 - Window + Init (Semaine 1) + +**Objectif** : Window SDL2 + bgfx initialized, clear screen + +- [ ] Setup SDL2 window +- [ ] Initialize bgfx avec window handle +- [ ] Clear screen avec couleur +- [ ] Main loop fonctionnel +- [ ] Event handling basique (close window) + +**Livrable** : Window qui affiche fond gris, ferme proprement + +--- + +### Phase 2 - Primitives 2D (Semaine 2) + +**Objectif** : DrawRect fonctionnel + +- [ ] Vertex layouts (ColorVertex, SpriteVertex) +- [ ] Shader compilation (color shader) +- [ ] DrawRect implementation +- [ ] Camera 2D orthographic +- [ ] Afficher 1 rectangle colorĂ© + +**Livrable** : FenĂȘtre avec rectangle rouge affichĂ© + +--- + +### Phase 3 - Sprite Rendering (Semaine 3) + +**Objectif** : DrawSprite fonctionnel + +- [ ] Texture loading (stb_image) +- [ ] Sprite shader (vertex + fragment) +- [ ] DrawSprite implementation (batched) +- [ ] Afficher 1 sprite texturĂ© + +**Livrable** : FenĂȘtre avec sprite test affichĂ© + +--- + +### Phase 4 - UI Elements (Semaine 4) + +**Objectif** : Text rendering + UI primitives + +- [ ] Font loading (stb_truetype ou FreeType) +- [ ] DrawText implementation +- [ ] UI element base class +- [ ] UIPanel, UIText primitives + +**Livrable** : FenĂȘtre avec panneau UI + texte + +--- + +## DĂ©pendances + +### Externes (Libraries) + +- **SDL2** : Window + input +- **bgfx** : Rendering abstraction +- **bx** : Base library (bgfx dependency) +- **bimg** : Image loading (bgfx dependency) +- **stb_image** : Texture loading +- **stb_truetype** ou **FreeType** : Font rendering + +### GroveEngine (Internes) + +- `IModule` interface +- `IDataNode` (config system) +- `IIO` (inter-module communication) + +--- + +## Test Case - Base AvancĂ©e + +### Validation Criteria + +**Window + UI 2D element = base avancĂ©e validĂ©e** si : + +1. ✅ Window SDL2 créée et stable +2. ✅ bgfx initialisĂ© et rendering fonctionnel +3. ✅ DrawRect affiche rectangle colorĂ© +4. ✅ DrawSprite affiche sprite texturĂ© +5. ✅ DrawText affiche texte (police) +6. ✅ UI element (panel) rendu correctement +7. ✅ Module intĂ©grĂ© dans GroveEngine (IModule interface) + +### Example Test Code + +```cpp +// main.cpp +int main() { + auto engine = grove::EngineFactory::CreateDebugEngine(); + + auto config = LoadConfig("render_module_config.json"); + engine->LoadModule("RenderModule", config); + + // Game loop + while (!should_quit) { + engine->Update(dt); + } + + return 0; +} + +// Dans RenderModule::update() +void RenderModule::update(float dt) { + BeginFrame(); + + // Test: Rectangle + DrawRect({100, 100, 200, 100}, Color{255, 0, 0, 255}); + + // Test: Sprite + DrawSprite(test_sprite); + + // Test: UI Panel + DrawRect({50, 50, 300, 200}, Color{64, 64, 64, 200}); + DrawText("Base AvancĂ©e OK!", main_font, {60, 60}); + + EndFrame(); +} +``` + +--- + +## Questions Ouvertes + +### Architecture + +1. **Text rendering** : stb_truetype (simple) ou FreeType (complet) ? +2. **Asset management** : AssetManager sĂ©parĂ© ou intĂ©grĂ© dans RenderModule ? +3. **Multi-window** : Support futur ou single window only ? + +### Performance + +4. **Sprite batching** : Sort by texture ou sort by Z-order ? +5. **Transient buffers** : OK pour MVP ou besoin persistent buffers ? + +### Integration + +6. **ImGui** : Garder ImGuiUI.h existant ou remplacer par custom UI ? +7. **Hot-reload** : Shader hot-reload nĂ©cessaire ou compilation statique OK ? + +--- + +## Ressources + +### Documentation bgfx + +- Repo : https://github.com/bkaradzic/bgfx +- Examples : https://github.com/bkaradzic/bgfx/tree/master/examples +- API docs : https://bkaradzic.github.io/bgfx/ + +### Tutorials 2D avec bgfx + +- bgfx example-26 (vectordisplay) +- NanoVG-bgfx : https://github.com/memononen/nanovg + +### SDL2 + +- Wiki : https://wiki.libsdl.org/ +- Lazy Foo tutorials : https://lazyfoo.net/tutorials/SDL/ + +--- + +## Liens Projets + +- **GroveEngine core** : `Projects/WIP/GroveEngine.md` +- **GroveEngine architecture** : `Projects/WIP/grove-sup.md` +- **Aissia** (utilisateur) : `Projects/WIP/AISSIA.md` +- **Pokrovsk** (utilisateur futur) : `Projects/CONCEPT/pokrovsk_last_day.md` + +--- + +**Créé** : 26 novembre 2025 +**Status** : Architecture planning +**Type** : Framework module (base avancĂ©e) +**Objectif** : Window + UI 2D rendering pour GroveEngine