From 4f92895fab88091fc1f1491b67ddc9fa69f51d5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Drago=C8=99-Andrei=20Bobu?= Date: Mon, 29 Jun 2026 00:05:50 +0300 Subject: [PATCH 1/3] Add architecture documentation --- README.md | 43 +++++++ docs/architecture-vision.md | 178 +++++++++++++++++++++++++++ docs/ml-native-direction.md | 182 ++++++++++++++++++++++++++++ docs/modernization-roadmap.md | 213 +++++++++++++++++++++++++++++++++ docs/runtime-loop-ownership.md | 157 ++++++++++++++++++++++++ docs/scene-json-model.md | 189 +++++++++++++++++++++++++++++ 6 files changed, 962 insertions(+) create mode 100644 README.md create mode 100644 docs/architecture-vision.md create mode 100644 docs/ml-native-direction.md create mode 100644 docs/modernization-roadmap.md create mode 100644 docs/runtime-loop-ownership.md create mode 100644 docs/scene-json-model.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..c523f61f --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +# Bleue Mer + +Bleue Mer is a bachelor-thesis-era game engine/editor prototype exploring a compact C++ runtime, a Unity-inspired object model, and a Processing-like creative coding API. The current repository contains: + +- a C++ OpenGL/GLUT engine layer with math primitives, render helpers, input, and `GameObject` abstractions; +- Python/PyQt editor prototypes for project creation, scene browsing, hierarchy display, assets, terminal, inspector, and scene view panels; +- several experimental C++ projects and demos. + +The project is best understood as a prototype for a future architecture rather than a finished engine. Its strongest direction is a C++ engine/editor stack where scenes are authored as data, loaded into runtime `GameObject`s, and rendered either natively or on the web. + +## Documentation map + +Start with these documents: + +1. [Architecture Vision](docs/architecture-vision.md) — the high-level direction for the engine, editor, data model, and web deployment. +2. [Scene and JSON Model](docs/scene-json-model.md) — how Processing-style code, Unity-like objects, and JSON scene files fit together. +3. [Runtime Loop Ownership](docs/runtime-loop-ownership.md) — how Qt, native runtime, and browser hosts should drive the engine without the engine owning the main loop. +4. [ML-Native Engine Direction](docs/ml-native-direction.md) — how native C++ machine-learning primitives could become first-class engine components. +5. [Modernization Roadmap](docs/modernization-roadmap.md) — an implementation sequence for turning the prototype into a coherent next-generation system. + +## Current architectural center + +The current C++ engine already has the vocabulary of the future system: + +- `Vector3` and `Color` define basic value types. +- `RenderEngine` exposes a small immediate drawing API. +- `GameEngine::GameObject` owns component-like data: `Transform`, `Rigidbody`, `Renderer`, and `Collider`. +- input is abstracted behind `GameEngine::Input`. + +The current editor prototype already points toward the authoring side: + +- projects contain `ProjectData.json`; +- scenes are placed under `Assets/Scenes`; +- the hierarchy reads scene JSON and displays scene/game-object names; +- the project page sketches a Unity-like editor layout. + +The next architectural milestone is to make these two halves share a formal scene model. + +## Recommended future identity + +> Bleue Mer should become a C++/Qt game and simulation editor with a Processing-like drawing layer, Unity-like `GameObject` behavior, JSON-authored scenes, native C++ ML components, and eventual WebAssembly/WebGL deployment. + +That identity keeps the original elegance of the engine while giving the project a clear path forward. diff --git a/docs/architecture-vision.md b/docs/architecture-vision.md new file mode 100644 index 00000000..e83d126e --- /dev/null +++ b/docs/architecture-vision.md @@ -0,0 +1,178 @@ +# Architecture Vision + +## One-sentence direction + +Bleue Mer should evolve into a C++/Qt game and simulation editor built around a loop-agnostic C++ engine core, a Processing-like immediate drawing API, a Unity-like `GameObject` scene model, JSON serialization, native ML components, and eventual web deployment through WebAssembly/WebGL. + +## Why this direction fits the existing project + +The current codebase already contains two compatible halves: + +1. **C++ runtime and engine vocabulary** + - math primitives; + - color primitives; + - immediate render helpers; + - input abstraction; + - `GameObject` with component-like fields. + +2. **Python/PyQt editor prototype vocabulary** + - project creation; + - project data; + - scene files; + - hierarchy panel; + - scene view; + - assets panel; + - inspector concept; + - run/build action. + +The missing bridge is not conceptual. The missing bridge is a formal shared runtime/editor model: + +```text +ProjectData.json + -> active scene JSON + -> C++ SceneLoader + -> Scene + -> GameObjects + -> Components + -> rendering, physics, input, ML behavior +``` + +## Target dependency direction + +The clean dependency direction is: + +```text +EditorQt ---> Engine +Runtime ---> Engine +WebHost ---> Engine +Engine -X-> EditorQt +Engine -X-> Runtime +Engine -X-> WebHost +``` + +The engine should not know whether it is running inside a Qt editor, a native executable, or a browser canvas. It should expose initialization, update, render, serialization, and component APIs. Hosts decide when and where to call those APIs. + +## Core layers + +A future version could be organized like this: + +```text +Engine/ + Core/ + Application + Scene + GameObject + Component + Behaviour + Time + Math/ + Vector2 + Vector3 + Color + Matrix + Rendering/ + Renderer + RenderCommand + PrimitiveRenderer + OpenGLBackend + WebGLBackend + Input/ + Input + KeyCode + Mouse + Serialization/ + ProjectSerializer + SceneSerializer + ModelSerializer + ML/ + Dataset + Model + LinearRegression + KMeans + DecisionTree + MLBehaviour + +EditorQt/ + MainWindow + SceneViewport + HierarchyPanel + InspectorPanel + AssetsPanel + ConsolePanel + MLPanel + +Runtime/ + main.cpp + NativeWindow + +Web/ + index.html + wasm bootstrap + asset manifest +``` + +## Engine core responsibilities + +The engine core should own: + +- scene data; +- game object identity and hierarchy; +- component data; +- behavior update ordering; +- render command generation; +- input state representation; +- serialization of engine-owned data; +- optional ML model execution. + +The engine core should **not** own: + +- the Qt application loop; +- the browser event loop; +- editor widgets; +- platform-specific window creation policy; +- editor-only selection state, gizmo state, or dock layout. + +## Editor responsibilities + +The C++/Qt editor should own: + +- project opening/creation UI; +- hierarchy display; +- inspector editing; +- asset browsing; +- scene viewport hosting; +- edit/play/pause state; +- saving and loading scenes through engine serializers; +- visual tools for ML datasets/models; +- build/export commands. + +The editor should manipulate actual engine `Scene` and `GameObject` instances in memory, not constantly shell out to separate helper programs. + +## Runtime responsibilities + +A standalone runtime should own: + +- creating a native window; +- loading a project/scene; +- running the game loop; +- forwarding input into the engine; +- calling `engine.update(dt)` and `engine.render()`; +- packaging assets for native distribution. + +## Web host responsibilities + +The web host should own: + +- loading the WASM module; +- fetching or mounting scene/assets files; +- connecting browser input to engine input; +- using the browser animation loop; +- rendering through WebGL or a WebGL-compatible backend. + +## Architectural rule of thumb + +If a feature is needed by editor, runtime, and web deployment, it belongs in `Engine`. + +If a feature is only a tool for authoring, visualization, docking, selection, or editing workflow, it belongs in `EditorQt`. + +If a feature only starts a platform-specific executable/window/canvas, it belongs in a host layer. diff --git a/docs/ml-native-direction.md b/docs/ml-native-direction.md new file mode 100644 index 00000000..e06ba942 --- /dev/null +++ b/docs/ml-native-direction.md @@ -0,0 +1,182 @@ +# ML-Native Engine Direction + +## Vision + +Bleue Mer can have a distinctive identity by treating machine learning as a native engine capability rather than an external Python-only workflow. + +The goal is not to clone all of scikit-learn. The goal is to implement a focused set of understandable C++ ML primitives that can be used directly by scenes, objects, simulations, and editor tools. + +## What ML-native means + +ML-native means: + +- models are implemented in C++; +- models can run inside the engine update loop; +- models can be attached to game objects as behaviours/components; +- model configuration can be serialized; +- the editor can inspect model inputs, outputs, and training data; +- web export can run the same model code through WASM. + +ML-native does **not** mean: + +- the runtime depends on Python; +- every scikit-learn feature must be reimplemented; +- training must be complex from the beginning; +- gameplay must block on heavyweight ML workflows. + +## First algorithms to implement + +Start with small, understandable algorithms: + +1. Linear Regression +2. Logistic Regression +3. K-Nearest Neighbors +4. K-Means +5. Perceptron +6. Simple Decision Tree +7. Tiny feed-forward neural network + +These algorithms are useful for demos, visualizations, and game/simulation behavior while remaining feasible to implement cleanly in C++. + +## Suggested ML module + +```text +Engine/ML/ + Tensor + Matrix + Dataset + Model + SupervisedModel + UnsupervisedModel + LinearRegression + LogisticRegression + KNearestNeighbors + KMeans + DecisionTree + ModelSerializer + MLBehaviour +``` + +## Runtime API sketch + +```cpp +ML::LinearRegression model; +model.fit(xTrain, yTrain); + +float prediction = model.predict({ ballX, ballY, paddleY })[0]; +``` + +For an engine object: + +```cpp +class MLBehaviour : public Behaviour +{ +public: + std::unique_ptr model; + InputBinding inputs; + OutputBinding outputs; + + void update(GameObject& self, Scene& scene, float dt) override + { + auto x = inputs.collect(self, scene); + auto y = model->predict(x); + outputs.apply(self, scene, y); + } +}; +``` + +## Example: ML-controlled paddle + +A strong first demo would be an ML-controlled paddle in the existing bouncer-style project. + +Inputs: + +```text +ball.position.x +ball.position.y +ball.velocity.x +ball.velocity.y +paddle.position.y +``` + +Output: + +```text +paddle.rigidbody.velocity.y +``` + +This demo would connect the whole vision: + +```text +GameObject scene model + + Processing-like visualization + + native C++ ML prediction + + editor-inspectable data + + possible web export +``` + +## Model serialization + +A model file can start as JSON: + +```json +{ + "Version": 1, + "Type": "LinearRegression", + "Inputs": [ + "ball.position.x", + "ball.position.y", + "ball.velocity.x", + "ball.velocity.y", + "paddle.position.y" + ], + "Outputs": [ + "paddle.rigidbody.velocity.y" + ], + "Weights": [0.2, -0.4, 0.7, 0.1, 0.9], + "Bias": 0.0 +} +``` + +This keeps ML assets aligned with scene/project serialization. + +## Editor support + +The editor can eventually include an ML panel with: + +- dataset viewer; +- model asset inspector; +- input/output binding editor; +- train/evaluate buttons; +- loss plot; +- decision boundary visualization; +- cluster visualization; +- model debug output during play mode. + +## Relationship to Processing-style projects + +Processing-style drawing is excellent for ML visualization: + +- draw regression lines; +- draw clusters; +- draw loss curves; +- draw decision boundaries; +- draw agent observations; +- draw model predictions. + +Unity-style GameObjects are excellent for ML behavior: + +- attach an ML model to an enemy; +- control a paddle; +- classify world states; +- select behaviors; +- drive procedural simulations. + +JSON is excellent for persistence: + +- store model parameters; +- store model bindings; +- store dataset references; +- store scene objects using ML behaviours. + +Together, these form a coherent ML-native engine model. diff --git a/docs/modernization-roadmap.md b/docs/modernization-roadmap.md new file mode 100644 index 00000000..37c4c00c --- /dev/null +++ b/docs/modernization-roadmap.md @@ -0,0 +1,213 @@ +# Modernization Roadmap + +This roadmap focuses on turning the prototype into a coherent next-generation engine/editor system without losing the simplicity and beauty of the original engine API. + +## Phase 0: Preserve the prototype + +Before rewriting, preserve what exists: + +- keep current demos available; +- document current engine API; +- keep the Python editor as historical/prototype reference; +- avoid rewriting everything before proving the new architecture. + +## Phase 1: CMake and C++ project structure + +Create a modern C++ layout: + +```text +Engine/ +EditorQt/ +Runtime/ +Tests/ +Projects/ +``` + +Use CMake targets: + +```text +bleuemer_engine +bleuemer_editor +bleuemer_runtime +bleuemer_tests +``` + +Goal: compile the engine as a reusable library. + +## Phase 2: Loop-agnostic engine core + +Extract the engine from hard ownership of any one windowing loop. + +Target API: + +```cpp +engine.initialize(); +engine.update(scene, dt); +engine.render(scene, renderer); +engine.shutdown(); +``` + +Success condition: a test or minimal host can call update/render without entering a GLUT-style permanent main loop. + +## Phase 3: Scene and GameObject model + +Add first-class runtime types: + +```text +Scene +GameObject +Transform +RendererComponent +Rigidbody +Collider +Behaviour +``` + +The current fixed-component style can be preserved initially. The first goal is not a perfect ECS. The first goal is a stable, serializable runtime object model. + +## Phase 4: Render command queue + +Unify immediate drawing and GameObject rendering through commands: + +```text +draw.circle(...) + -> RenderCommand + +object.renderer.render(...) + -> RenderCommand + +backend.flush(commands) + -> OpenGL/WebGL draw calls +``` + +Success condition: Processing-style calls and scene-object rendering share the same backend path. + +## Phase 5: Scene JSON serialization + +Implement: + +```text +ProjectSerializer +SceneSerializer +ComponentSerializer +``` + +Success condition: + +```text +Scene JSON -> C++ Scene -> rendered objects +``` + +This is the central architecture proof. + +## Phase 6: Minimal C++/Qt editor + +Do not recreate every Python editor feature first. Build only: + +- main window; +- hierarchy panel; +- inspector panel; +- `QOpenGLWidget` scene viewport; +- asset browser stub. + +Success condition: + +```text +Open scene JSON + -> hierarchy displays objects + -> inspector edits transform/color + -> viewport updates + -> save writes JSON +``` + +## Phase 7: Native runtime host + +Create a standalone runtime executable: + +```text +bleuemer_runtime Projects/dvd_bouncer/ProjectData.json +``` + +Success condition: + +```text +runtime loads project +runtime loads active scene +runtime runs update/render loop +``` + +## Phase 8: Processing-style project layer + +Add a clean sketch API: + +```cpp +class Sketch +{ +public: + virtual void start() {} + virtual void update(float dt) {} +}; +``` + +Allow projects to combine: + +```text +scene-loaded GameObjects ++ immediate Processing-style drawing ++ custom C++ behavior +``` + +## Phase 9: ML-native module + +Implement a first ML slice: + +1. Matrix/Tensor basics; +2. Dataset container; +3. LinearRegression; +4. model serialization; +5. `MLBehaviour` component; +6. ML-controlled paddle demo. + +Success condition: + +```text +GameObject behavior uses native C++ model prediction during update +``` + +## Phase 10: Web export + +Compile engine/runtime to WASM after the loop-agnostic architecture is proven. + +Export package: + +```text +dist/ + index.html + engine.wasm + project.json + assets/ + scenes/ + models/ +``` + +Success condition: + +```text +same scene JSON runs natively and in browser +``` + +## Recommended order of proof + +The strongest proof sequence is: + +```text +1. C++ engine library +2. Scene JSON loads into C++ objects +3. Objects render through command queue +4. Qt viewport renders the same scene +5. Runtime executable loads the same scene +6. ML component drives an object +7. WASM runtime loads the same scene +``` + +Do not start with web deployment or full ML tooling. Build the shared core first. diff --git a/docs/runtime-loop-ownership.md b/docs/runtime-loop-ownership.md new file mode 100644 index 00000000..59d65702 --- /dev/null +++ b/docs/runtime-loop-ownership.md @@ -0,0 +1,157 @@ +# Runtime Loop Ownership + +## Core rule + +The engine should not own the main loop. + +Instead: + +```text +Host owns loop. +Engine exposes frame functions. +``` + +This is essential because Bleue Mer may run in at least three hosts: + +1. C++/Qt editor; +2. native standalone runtime; +3. browser/WebAssembly runtime. + +Each host has different loop rules. + +## Current prototype constraint + +The current renderer is GLUT-centered. It creates the window, registers callbacks, invokes the start callback, and enters `glutMainLoop()`. That is suitable for demos but too rigid for Qt and browser deployment. + +## Desired engine API + +The engine should expose something like: + +```cpp +class Engine +{ +public: + void initialize(); + void shutdown(); + + void update(Scene& scene, float deltaTime); + void render(Scene& scene, Renderer& renderer); +}; +``` + +The host decides when to call these functions. + +## Qt editor loop + +In editor mode, Qt owns the loop: + +```cpp +int main(int argc, char** argv) +{ + QApplication app(argc, argv); + + EditorContext context; + MainWindow window(&context); + window.show(); + + return app.exec(); +} +``` + +A `QTimer` or viewport update event can drive frames: + +```cpp +connect(timer, &QTimer::timeout, this, [this]() +{ + float dt = clock.deltaTime(); + + if (editorContext.isPlaying) + { + engine.update(editorContext.scene, dt); + } + + sceneViewport->update(); +}); +``` + +The `QOpenGLWidget` performs rendering: + +```cpp +void SceneViewport::paintGL() +{ + renderer.beginFrame(); + engine.render(editorContext.scene, renderer); + renderer.endFrame(); +} +``` + +## Native runtime loop + +A standalone runtime can own a traditional game loop: + +```cpp +while (window.isOpen()) +{ + float dt = clock.deltaTime(); + + input.poll(); + engine.update(scene, dt); + + renderer.beginFrame(); + engine.render(scene, renderer); + renderer.endFrame(); +} +``` + +This host may use GLFW, SDL, Qt, or another backend. The engine core should not care. + +## Web loop + +In the browser, the browser owns the event loop. With Emscripten, the host would register a frame callback: + +```cpp +emscripten_set_main_loop(frame, 0, true); +``` + +Then each browser frame calls: + +```cpp +void frame() +{ + float dt = webClock.deltaTime(); + + input.updateFromBrowser(); + engine.update(scene, dt); + engine.render(scene, renderer); +} +``` + +The engine remains the same. Only the host changes. + +## Why this matters + +Loop ownership determines whether the engine can be embedded, tested, exported, and reused. + +If the engine owns `mainLoop()`, it is hard to embed in Qt and hard to port to the browser. + +If the host owns the loop, the same engine can run in: + +```text +Qt editor +native game executable +browser canvas +unit tests +headless simulations +ML training/evaluation tools +``` + +## Recommended transition path + +1. Keep existing GLUT demos working as a legacy host. +2. Extract engine update/render functions from GLUT callbacks. +3. Make GLUT call those functions instead of owning all engine behavior. +4. Add a Qt viewport host. +5. Add a standalone native host. +6. Add a web host later. + +The important refactor is not replacing GLUT immediately. The important refactor is making GLUT just one host among several. diff --git a/docs/scene-json-model.md b/docs/scene-json-model.md new file mode 100644 index 00000000..60b468e2 --- /dev/null +++ b/docs/scene-json-model.md @@ -0,0 +1,189 @@ +# Scene and JSON Model + +## The three authoring styles + +Bleue Mer can support three complementary authoring styles. + +### 1. Processing-style sketch mode + +A project can draw directly with immediate functions: + +```cpp +void update(float dt) +{ + draw.background(Color::black); + draw.stroke(Color::cyan); + draw.circle(Vector3(0, 0, 0), 0.2f); +} +``` + +This mode is ideal for procedural art, math visualizations, simulations, fast experiments, and thesis-style demos. + +### 2. Unity-style scene mode + +A project can operate on persistent objects: + +```cpp +Scene scene = SceneSerializer::Load("Assets/Scenes/Main.json"); + +void update(float dt) +{ + scene.update(dt); + scene.render(renderer); +} +``` + +This mode is ideal for editor-authored projects, games, reusable assets, object inspection, collision, and component behavior. + +### 3. Hybrid mode + +A project can combine both: + +```cpp +void update(float dt) +{ + draw.background(Color::darkGray); + + scene.update(dt); + scene.render(renderer); + + draw.stroke(Color::yellow); + draw.line(Vector3(-1, 0, 0), Vector3(1, 0, 0)); +} +``` + +This hybrid model is the strongest identity for Bleue Mer: Processing-like expression plus Unity-like structure. + +## What JSON should store + +JSON should store persistent authored data: + +- project metadata; +- active scene path; +- scene name and IDs; +- game objects; +- transform values; +- renderer configuration; +- collider configuration; +- rigidbody values; +- behavior references/configuration; +- ML model references and bindings; +- asset references. + +JSON should not try to store every temporary immediate drawing command. Immediate drawing belongs to code. Persistent world objects belong to scene data. + +## Proposed project file + +```json +{ + "Version": 1, + "Name": "dvd_bouncer", + "ActiveScene": "Assets/Scenes/SampleScene.json", + "Scenes": [ + "Assets/Scenes/SampleScene.json" + ], + "AssetRoots": [ + "Assets" + ] +} +``` + +## Proposed scene file + +```json +{ + "Version": 1, + "ID": 0, + "Name": "SampleScene", + "Background": { "r": 0.02, "g": 0.02, "b": 0.04, "a": 1.0 }, + "GameObjects": [ + { + "ID": 1, + "Name": "Ball", + "Enabled": true, + "Transform": { + "Position": { "x": 0.0, "y": 0.0, "z": 0.0 }, + "Rotation": { "x": 0.0, "y": 0.0, "z": 0.0 }, + "Scale": { "x": 0.1, "y": 0.1, "z": 1.0 } + }, + "Renderer": { + "Shape": "Circle", + "Color": { "r": 1.0, "g": 1.0, "b": 1.0, "a": 1.0 } + }, + "Rigidbody": { + "Velocity": { "x": 0.5, "y": 0.25, "z": 0.0 } + }, + "Collider": { + "Type": "Circle", + "Radius": 0.05 + }, + "Behaviours": [ + { + "Type": "BounceBehaviour", + "Config": { + "BoundsMin": { "x": -1.0, "y": -1.0, "z": 0.0 }, + "BoundsMax": { "x": 1.0, "y": 1.0, "z": 0.0 } + } + } + ] + } + ] +} +``` + +## Runtime loading flow + +```text +ProjectSerializer::Load(ProjectData.json) + -> project.ActiveScene + -> SceneSerializer::Load(active scene path) + -> Scene + -> GameObject instances + -> component values + -> behavior instances/configuration +``` + +## Editor flow + +```text +Open project + -> load ProjectData.json + -> load active Scene JSON + -> populate Hierarchy + -> show selected object in Inspector + -> render Scene in Viewport +``` + +When the user edits a transform in the inspector: + +```text +Inspector value changed + -> modify GameObject.Transform in memory + -> viewport updates immediately + -> Save Scene writes JSON +``` + +## Processing draw and GameObject rendering should share a backend + +Both immediate drawing and object rendering should become render commands: + +```text +Processing API: + draw.circle(...) + -> RenderCommand(type=Circle) + +GameObject Renderer: + object.render(...) + -> RenderCommand(type=Rect/Circle/Sprite/Mesh) +``` + +Then platform backends consume the same commands: + +```text +Render commands + -> native OpenGL backend + -> Qt OpenGL viewport backend + -> WebGL/WASM backend +``` + +This makes the engine portable and keeps the public API simple. From 617e682ad819f87dcaaec2821b4f3c6cca2d6569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Drago=C8=99-Andrei=20Bobu?= Date: Mon, 29 Jun 2026 00:20:46 +0300 Subject: [PATCH 2/3] Document editor CLI boundary debt --- README.md | 1 + docs/architecture-vision.md | 2 + docs/editor-cli-debt.md | 278 ++++++++++++++++++++++++++++++++++ docs/modernization-roadmap.md | 4 + 4 files changed, 285 insertions(+) create mode 100644 docs/editor-cli-debt.md diff --git a/README.md b/README.md index c523f61f..b6679040 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Start with these documents: 3. [Runtime Loop Ownership](docs/runtime-loop-ownership.md) — how Qt, native runtime, and browser hosts should drive the engine without the engine owning the main loop. 4. [ML-Native Engine Direction](docs/ml-native-direction.md) — how native C++ machine-learning primitives could become first-class engine components. 5. [Modernization Roadmap](docs/modernization-roadmap.md) — an implementation sequence for turning the prototype into a coherent next-generation system. +6. [Editor CLI and Process Boundary Debt](docs/editor-cli-debt.md) — why the old GUI subprocess/argv communication should be retired in favor of typed services. ## Current architectural center diff --git a/docs/architecture-vision.md b/docs/architecture-vision.md index e83d126e..bcf29e5d 100644 --- a/docs/architecture-vision.md +++ b/docs/architecture-vision.md @@ -148,6 +148,8 @@ The C++/Qt editor should own: The editor should manipulate actual engine `Scene` and `GameObject` instances in memory, not constantly shell out to separate helper programs. +The previous subprocess-heavy GUI communication model should be treated as prototype glue. A C++/Qt rewrite should centralize project, scene, asset, and build operations behind typed services instead of routing internal editor state through command-line arguments and parsed stdout. + ## Runtime responsibilities A standalone runtime should own: diff --git a/docs/editor-cli-debt.md b/docs/editor-cli-debt.md new file mode 100644 index 00000000..309d1356 --- /dev/null +++ b/docs/editor-cli-debt.md @@ -0,0 +1,278 @@ +# Editor CLI and Process Boundary Debt + +## The uncomfortable truth + +The current Python editor prototype uses command-line subprocess calls as an internal communication mechanism. That made sense for fast thesis/demo progress, but it is not a good long-term architecture. + +The pattern looks roughly like this: + +```text +GUI widget + -> subprocess: python -m Some.Editor.Module --some-arg value + -> module parses argv + -> module prints a tagged line + -> GUI parses stdout +``` + +This creates a fragile system where editor state is passed through process arguments, stdout strings, and implicit conventions instead of through typed in-memory APIs. + +## Why it became spaghetti + +This style usually starts harmlessly: + +```text +"I just need the GUI to ask the file manager whether this path is valid." +``` + +Then it spreads: + +```text +open project +create project +get latest scene +get config +create empty scene +run project +``` + +Every interaction becomes a mini command-line protocol. Eventually the editor is not one application anymore; it is a network of small programs calling each other by arguments and parsing each other's printed output. + +That is workable for a demo. It is painful for an engine editor. + +## Problems caused by internal CLI calls + +### 1. No typed boundary + +A function call can return a `Project`, `Scene`, `Path`, or `Result`. + +A subprocess returns: + +```text +stdout +stderr +exit code +``` + +The caller then has to search for magic prefixes like: + +```text +isValidProject: true +LatestSavedScene: path/to/file.json +``` + +That means the real API is hidden in string formatting. + +### 2. Weak error handling + +When the subprocess fails, the caller often knows only that the command failed. It may not know whether the issue was: + +- missing project file; +- malformed JSON; +- missing scene folder; +- invalid command arguments; +- Python import failure; +- an internal exception; +- a user-facing validation error. + +A real API can return structured errors. A subprocess protocol usually degrades into printing text. + +### 3. State fragmentation + +The editor should have a shared in-memory concept of: + +```text +current project +active scene +selected object +dirty state +asset root +play/edit mode +``` + +With subprocess calls, each command reconstructs its own partial view from paths and arguments. State becomes scattered instead of owned by an `EditorContext`. + +### 4. Harder refactoring + +If a GUI panel depends on a printed line from a helper command, renaming that line becomes a breaking API change. + +The protocol is not discoverable through the type system. It is only discoverable by reading both the caller and the subprocess implementation. + +### 5. Bad fit for a C++/Qt rewrite + +A future C++/Qt editor should not preserve this style. The rewrite should replace internal process calls with direct services: + +```cpp +ProjectService projectService; +SceneService sceneService; +AssetService assetService; +BuildService buildService; +``` + +The editor should call these services directly and receive typed results. + +## What the future boundary should look like + +The editor should have a central context: + +```cpp +class EditorContext +{ +public: + Project project; + Scene activeScene; + GameObjectId selectedObject; + bool isDirty = false; + bool isPlaying = false; +}; +``` + +Panels should communicate through this context and services: + +```text +HierarchyPanel + reads EditorContext.activeScene + writes EditorContext.selectedObject + +InspectorPanel + reads selected GameObject + mutates component data + marks scene dirty + +SceneViewport + renders EditorContext.activeScene + +AssetsPanel + reads Project asset roots + +ProjectService + opens/saves project data + +SceneService + loads/saves scene data +``` + +## Recommended service layer + +A clean C++/Qt editor could use services like: + +```cpp +class ProjectService +{ +public: + Result openProject(const Path& path); + Result saveProject(const Project& project); + Result createProject(const ProjectCreateInfo& info); +}; + +class SceneService +{ +public: + Result loadScene(const Path& path); + Result saveScene(const Scene& scene, const Path& path); + Scene createEmptyScene(std::string name); +}; + +class AssetService +{ +public: + std::vector listAssets(const Project& project); + Result importAsset(const Path& source, const Path& destination); +}; + +class BuildService +{ +public: + Result buildProject(const Project& project, BuildTarget target); + Result runProject(const BuildArtifact& artifact); +}; +``` + +The GUI remains a GUI. The engine/editor logic lives in testable services. + +## What should still be allowed to use processes + +Not every subprocess is bad. Some boundaries are naturally process-based: + +- launching a standalone game runtime; +- compiling a project; +- invoking an external compiler/toolchain; +- starting a web export pipeline; +- opening a file browser; +- running optional external ML/data tools. + +The rule should be: + +```text +Use processes for external tools and runtime boundaries. +Do not use processes for internal editor state and data flow. +``` + +## Migration path from the current prototype + +### Step 1: Name the anti-pattern + +Document that subprocess-based editor communication was prototype glue, not the intended architecture. + +### Step 2: Extract pure functions + +Move logic like project validation, project creation, scene loading, and scene discovery into pure functions or classes. + +Bad: + +```text +GUI -> subprocess -> argparse -> filesystem -> print result -> parse stdout +``` + +Better: + +```text +GUI -> ProjectService::openProject(path) -> Result +``` + +### Step 3: Keep CLI wrappers only as thin shells + +If command-line tools are still useful, make them wrappers around the real service layer: + +```text +CLI command + -> ProjectService + -> typed result + -> formatted terminal output +``` + +The CLI should not be the source of truth. + +### Step 4: In the C++/Qt rewrite, start with services + +Before building every panel, create: + +```text +EditorContext +ProjectService +SceneService +AssetService +BuildService +``` + +Then panels can remain simple and avoid spaghetti from the beginning. + +## Desired end state + +```text +Editor UI + -> typed services + -> engine/editor data model + -> serializers/build/runtime hosts +``` + +Not: + +```text +Editor UI + -> subprocess + -> argparse + -> print tagged stdout + -> parse string in another widget +``` + +The current CLI-heavy approach was useful glue for getting the demo moving. The next architecture should treat it as technical debt to retire, not as a pattern to preserve. diff --git a/docs/modernization-roadmap.md b/docs/modernization-roadmap.md index 37c4c00c..29d3470e 100644 --- a/docs/modernization-roadmap.md +++ b/docs/modernization-roadmap.md @@ -11,6 +11,10 @@ Before rewriting, preserve what exists: - keep the Python editor as historical/prototype reference; - avoid rewriting everything before proving the new architecture. +## Phase 0.5: Retire internal CLI glue + +The Python prototype used subprocess calls and argument parsing for internal editor communication. Do not carry that pattern into the C++/Qt rewrite. Before building new panels, define typed services for project, scene, asset, and build operations. CLI commands may remain as external wrappers, but they should call the same services rather than being the primary editor API. + ## Phase 1: CMake and C++ project structure Create a modern C++ layout: From c9122cccc95b1f13ba0cbd74ca8eff93d2c3d451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Drago=C8=99-Andrei=20Bobu?= Date: Mon, 29 Jun 2026 00:20:51 +0300 Subject: [PATCH 3/3] Add branch and PR sequencing plan --- README.md | 1 + docs/branch-pr-plan.md | 427 ++++++++++++++++++++++++++++++++++ docs/modernization-roadmap.md | 2 + 3 files changed, 430 insertions(+) create mode 100644 docs/branch-pr-plan.md diff --git a/README.md b/README.md index b6679040..2d9eb72a 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Start with these documents: 4. [ML-Native Engine Direction](docs/ml-native-direction.md) — how native C++ machine-learning primitives could become first-class engine components. 5. [Modernization Roadmap](docs/modernization-roadmap.md) — an implementation sequence for turning the prototype into a coherent next-generation system. 6. [Editor CLI and Process Boundary Debt](docs/editor-cli-debt.md) — why the old GUI subprocess/argv communication should be retired in favor of typed services. +7. [Branch and Pull Request Plan](docs/branch-pr-plan.md) — ordered future branch/PR sequence for engine, editor, runtime, ML, web, and cleanup work. ## Current architectural center diff --git a/docs/branch-pr-plan.md b/docs/branch-pr-plan.md new file mode 100644 index 00000000..c1ac6c1b --- /dev/null +++ b/docs/branch-pr-plan.md @@ -0,0 +1,427 @@ +# Branch and Pull Request Plan + +This plan describes the order of future branches and pull requests for turning the prototype into a coherent engine/editor stack. The goal is to keep every PR reviewable, preserve the existing demos, and avoid mixing architecture, build-system work, editor rewrites, runtime changes, ML work, and web export in one giant branch. + +## Branch naming convention + +Use short branch names with an ordered prefix: + +```text +roadmap/00-docs-and-inventory +engine/01-cmake-library +engine/02-loop-agnostic-core +engine/03-scene-model +engine/04-render-command-queue +serialization/05-scene-json +editor/06-qt-shell +editor/07-qt-scene-editing +runtime/08-native-player +sketch/09-processing-layer +ml/10-core-models +ml/11-ml-behaviour-demo +web/12-wasm-export +cleanup/13-retire-python-editor-glue +``` + +The number is not about urgency alone. It is about dependency order. + +## PR 00: Documentation and repository inventory + +**Branch:** `roadmap/00-docs-and-inventory` + +**Purpose:** Establish shared language before code starts moving. + +**Should include:** + +- architecture documentation; +- current repository inventory; +- list of demos and their dependencies; +- known technical debt; +- decision log for C++/Qt, JSON scenes, loop ownership, ML-native direction, and web deployment. + +**Should not include:** + +- large code movement; +- build-system rewrite; +- editor rewrite. + +**Exit criteria:** + +- contributors understand the intended future shape; +- old prototype shortcuts are explicitly marked as prototype shortcuts; +- no one has to infer the architecture only from code. + +## PR 01: CMake engine library foundation + +**Branch:** `engine/01-cmake-library` + +**Purpose:** Make the C++ engine build as a reusable library target. + +**Should include:** + +- root `CMakeLists.txt`; +- `bleuemer_engine` target; +- existing engine sources compiled through CMake; +- minimal example/demo target if practical; +- documented build commands. + +**Should not include:** + +- Qt editor; +- scene serialization; +- renderer redesign; +- ML. + +**Exit criteria:** + +```text +cmake -S . -B build +cmake --build build +``` + +builds the engine target. + +## PR 02: Loop-agnostic engine core + +**Branch:** `engine/02-loop-agnostic-core` + +**Purpose:** Separate engine update/render calls from GLUT owning the entire lifecycle. + +**Should include:** + +- an `Engine` or `Application` core API; +- `initialize`, `update`, `render`, and `shutdown` style functions; +- legacy GLUT host adapted to call the new API; +- no behavior change for existing demos if possible. + +**Should not include:** + +- full renderer abstraction; +- Qt viewport; +- scene JSON; +- web export. + +**Exit criteria:** + +- the engine can be advanced one frame by a host; +- GLUT becomes one host, not the engine architecture itself; +- future Qt and web hosts have a clean entry point. + +## PR 03: Runtime scene and GameObject model + +**Branch:** `engine/03-scene-model` + +**Purpose:** Add first-class `Scene` ownership around the existing `GameObject` direction. + +**Should include:** + +- `Scene` type; +- object collection; +- scene-level update/render traversal; +- stable IDs or handles if needed; +- a minimal behavior interface if it can remain small. + +**Should not include:** + +- JSON loading yet; +- full ECS; +- Qt inspector; +- ML behavior. + +**Exit criteria:** + +- code can create a `Scene`, add objects, update it, and render it; +- existing immediate drawing style still works. + +## PR 04: Render command queue + +**Branch:** `engine/04-render-command-queue` + +**Purpose:** Make Processing-style drawing and `GameObject` rendering share one rendering path. + +**Should include:** + +- `RenderCommand` type; +- command buffer or queue; +- primitive draw commands for rect, circle, line, point; +- backend flush path for the existing OpenGL implementation. + +**Should not include:** + +- Qt renderer backend; +- WebGL backend; +- material/mesh system unless absolutely minimal. + +**Exit criteria:** + +- immediate draw calls produce commands; +- object rendering produces commands; +- existing OpenGL backend can draw those commands. + +## PR 05: Scene JSON serialization + +**Branch:** `serialization/05-scene-json` + +**Purpose:** Make scenes loadable and saveable as data. + +**Should include:** + +- project metadata shape; +- scene JSON parser/writer; +- component serialization for transform, renderer, rigidbody, collider; +- sample scene file; +- tests for load/save roundtrips if possible. + +**Should not include:** + +- Qt editor; +- web export; +- ML model serialization. + +**Exit criteria:** + +```text +Scene JSON -> C++ Scene -> renderable objects +C++ Scene -> Scene JSON +``` + +works for the basic object model. + +## PR 06: Minimal C++/Qt editor shell + +**Branch:** `editor/06-qt-shell` + +**Purpose:** Create the new editor application without recreating every old panel. + +**Should include:** + +- Qt application target; +- main window; +- dock/panel layout; +- empty hierarchy, inspector, assets, console, and scene viewport placeholders; +- shared `EditorContext` type. + +**Should not include:** + +- full scene editing; +- ML panel; +- web export; +- replacing old Python editor yet. + +**Exit criteria:** + +- C++/Qt editor opens; +- panels are visible; +- it links against the engine library. + +## PR 07: Qt scene loading, hierarchy, inspector, and viewport + +**Branch:** `editor/07-qt-scene-editing` + +**Purpose:** Make the Qt editor operate on real engine scene data. + +**Should include:** + +- open project/scene flow; +- hierarchy populated from `Scene`; +- object selection; +- inspector editing for transform and renderer color/shape; +- `QOpenGLWidget` scene rendering; +- save scene. + +**Should not include:** + +- full asset importing; +- advanced gizmos; +- ML panel; +- web export. + +**Exit criteria:** + +```text +Open scene JSON + -> hierarchy shows objects + -> inspector edits object + -> viewport updates + -> save writes JSON +``` + +## PR 08: Native runtime/player host + +**Branch:** `runtime/08-native-player` + +**Purpose:** Create a standalone player that loads and runs project data outside the editor. + +**Should include:** + +- runtime executable target; +- project/scene loading; +- native window host; +- input forwarding; +- update/render loop using the loop-agnostic engine API. + +**Should not include:** + +- editor features; +- web export; +- ML training UI. + +**Exit criteria:** + +```text +bleuemer_runtime path/to/ProjectData.json +``` + +loads the active scene and runs it. + +## PR 09: Processing-style sketch layer + +**Branch:** `sketch/09-processing-layer` + +**Purpose:** Preserve and formalize the Processing-like authoring style. + +**Should include:** + +- `Sketch` or similar base class/interface; +- `start/setup` and `update/draw` style lifecycle; +- immediate drawing wrappers over the render command queue; +- example sketch project. + +**Should not include:** + +- editor rewrite work; +- ML; +- web export. + +**Exit criteria:** + +- a code-first Processing-style project can run; +- a hybrid project can combine scene-loaded objects and immediate drawing. + +## PR 10: Native ML core primitives + +**Branch:** `ml/10-core-models` + +**Purpose:** Add the first small C++ ML module. + +**Should include:** + +- small matrix/vector helpers if needed; +- dataset container; +- `Model` interface; +- `LinearRegression` as the first implemented model; +- simple tests or example usage. + +**Should not include:** + +- editor ML panel; +- every scikit-learn algorithm; +- object behavior integration yet. + +**Exit criteria:** + +- a model can be fit or loaded; +- prediction works in C++ without Python runtime dependency. + +## PR 11: ML behaviour and demo integration + +**Branch:** `ml/11-ml-behaviour-demo` + +**Purpose:** Connect ML to the engine object model. + +**Should include:** + +- `MLBehaviour` or equivalent component/behavior; +- model input/output binding concept; +- first demo such as ML-controlled paddle; +- model serialization if not already included. + +**Should not include:** + +- full ML editor tooling; +- complex neural networks; +- web export unless trivial. + +**Exit criteria:** + +- a `GameObject` can use native C++ model prediction during update. + +## PR 12: Web/WASM export proof + +**Branch:** `web/12-wasm-export` + +**Purpose:** Prove the architecture can run in a browser. + +**Should include:** + +- Emscripten build path; +- minimal web host; +- asset loading strategy; +- canvas/WebGL rendering path or compatible backend; +- sample exported scene. + +**Should not include:** + +- complete web editor; +- advanced asset pipeline; +- large ML demos. + +**Exit criteria:** + +- the same simple scene can run natively and in a browser. + +## PR 13: Retire or quarantine Python editor glue + +**Branch:** `cleanup/13-retire-python-editor-glue` + +**Purpose:** Reduce confusion once the C++/Qt path exists. + +**Should include:** + +- mark old Python editor as legacy, historical, or prototype; +- move it under a clear legacy folder if desired; +- remove internal CLI glue from the active path; +- keep samples if they are still useful. + +**Should not include:** + +- risky deletion before replacement exists; +- changing engine behavior. + +**Exit criteria:** + +- the active architecture is C++ engine + C++/Qt editor + runtime host; +- old subprocess-based GUI glue is no longer the recommended path. + +## Parallel work rules + +Some PRs can be prepared in parallel after their dependencies are clear: + +```text +PR 06 Qt shell can start after PR 01, but real scene editing needs PR 05. +PR 10 ML core can start after PR 01, but ML behaviour needs PR 03. +PR 12 web export should wait until PR 02 and PR 04 are stable. +``` + +Avoid parallel branches that modify the same architectural seam. For example, do not rewrite renderer ownership in one branch while another branch embeds the renderer in Qt. + +## Recommended merge order + +```text +00 docs/inventory +01 CMake engine library +02 loop-agnostic core +03 scene model +04 render command queue +05 scene JSON serialization +06 Qt editor shell +07 Qt scene editing +08 native runtime/player +09 Processing sketch layer +10 ML core primitives +11 ML behaviour demo +12 WASM/web export proof +13 retire Python editor glue +``` + +This order makes each later branch stand on an explicit foundation instead of depending on hidden assumptions. diff --git a/docs/modernization-roadmap.md b/docs/modernization-roadmap.md index 29d3470e..89edeceb 100644 --- a/docs/modernization-roadmap.md +++ b/docs/modernization-roadmap.md @@ -2,6 +2,8 @@ This roadmap focuses on turning the prototype into a coherent next-generation engine/editor system without losing the simplicity and beauty of the original engine API. +For a branch-by-branch implementation sequence, see [Branch and Pull Request Plan](branch-pr-plan.md). + ## Phase 0: Preserve the prototype Before rewriting, preserve what exists: