From 15ba38fb7e0ac0e245ddd09e7e590e472d956861 Mon Sep 17 00:00:00 2001 From: MartinFillon Date: Sun, 30 Nov 2025 11:20:35 +0100 Subject: [PATCH 1/9] docs(ecs): document ecs and design choices --- docs/Registry.md | 19 ++++ docs/Writing_Web_Assembly.md | 15 +++ packages/ecs-lib/wasm/Entity.hpp | 16 +++ packages/ecs-lib/wasm/Registry.hpp | 162 ++++++++++++++++++++++++----- 4 files changed, 184 insertions(+), 28 deletions(-) create mode 100644 docs/Registry.md create mode 100644 docs/Writing_Web_Assembly.md diff --git a/docs/Registry.md b/docs/Registry.md new file mode 100644 index 0000000..af5852c --- /dev/null +++ b/docs/Registry.md @@ -0,0 +1,19 @@ +# Registry + +The registry class is written in C++ and exposed to WebAssembly using Emscripten. +This choice was made to leverage the performance benefits of C++ for managing entities and components in an ECS architecture. +Emscripten allows us to compile C++ code into WebAssembly, which can then be +used in web applications, providing a bridge between high-performance C++ code and JavaScript. + + +## Design Choices + +This design makes some trade-offs between performance and ease of use. A pure C++ ECS would have been easier to use but having to bind it as us make choices that impact usability. + +### Const Correctness + +In a regular C++ ECS, const correctness is a given, but when exposing C++ to WebAssembly, as in C++ we can force constant of return values. But in WebAssembly, the concept of const correctness does not directly translate to JavaScript. Therefore, methods that would typically return const references in C++ may return non-const references or copies when exposed to WebAssembly. We deciced to keep the const correctness in the C++ code to maintain clarity and intent within the C++ domain, even if it doesn't fully carry over to the WebAssembly interface. + +### Error Handling + +Any thrown exceptions in C++ will result in a runtime error in JavaScript. The problem with this approach is that the error messages may not be as descriptive or user-friendly as native JavaScript errors. As every error thrown in C++ will be caught as a generic runtime error in JavaScript, it can make debugging more challenging. To mitigate this, we recommend thorough testing and validation within the C++ code to catch potential issues before they propagate to the WebAssembly layer. diff --git a/docs/Writing_Web_Assembly.md b/docs/Writing_Web_Assembly.md new file mode 100644 index 0000000..c1f6579 --- /dev/null +++ b/docs/Writing_Web_Assembly.md @@ -0,0 +1,15 @@ +# Writing Web Assembly + +## Code Splitting + +When writing Web Assembly modules, it's important to consider code splitting for readability and maintainability. We try to split binding and code logic into separate files where possible. This helps keep the codebase organized and makes it easier to navigate. + +For example, in the ECS package, the binding logic is in `.cpp` files, while the core logic resides in `.hpp` files. This separation allows developers to focus on either the binding or the logic without being overwhelmed by both at the same time. + +## Documentation + +When documenting Web Assembly modules, we follow a similar approach to C++ documentation. We use Doxygen-style comments to provide clear and concise explanations of classes, methods, and parameters. This documentation is crucial for developers who will be using or maintaining the Web Assembly modules, as it provides necessary context and usage information. + +## Logging + +Logging in Web Assembly is costly memory-wise due to the interaction between C++ and JavaScript. Therefore, we recommend to log from the JavaScript side whenever possible. If logging from C++ is necessary, be aware of the potential performance implications and memory leaks. Web assembly vm is memory limited, so excessive logging will lead to out-of-memory errors. diff --git a/packages/ecs-lib/wasm/Entity.hpp b/packages/ecs-lib/wasm/Entity.hpp index ddc0381..40ed54a 100644 --- a/packages/ecs-lib/wasm/Entity.hpp +++ b/packages/ecs-lib/wasm/Entity.hpp @@ -18,13 +18,29 @@ namespace nfo { class Entity { public: + /** + * Create an entity from an ID. + * + * @param id The ID of the entity. + * @return An Entity instance. + */ explicit Entity(const std::size_t id) : _id(id) {} + /** + * Convert the entity to its ID. + * + * @return The ID of the entity. + */ operator std::size_t() const { return _id; } + /** + * Get the ID of the entity. + * + * @return The ID of the entity. + */ [[nodiscard]] std::size_t get_id() const { return _id; diff --git a/packages/ecs-lib/wasm/Registry.hpp b/packages/ecs-lib/wasm/Registry.hpp index 566df82..9084bda 100644 --- a/packages/ecs-lib/wasm/Registry.hpp +++ b/packages/ecs-lib/wasm/Registry.hpp @@ -28,20 +28,28 @@ namespace nfo { class Registry { public: - SparseArray ®ister_component(const Component &c) + /** + * Register a component type in the registry. + * + * @param conponent An instance of the component to register. + * @return A reference to the SparseArray that will hold all components of this type. + * @throws std::runtime_error if the component type is "entity", "id", + * or UNKNOWN_COMPONENT_TYPE. + */ + SparseArray ®ister_component(const Component &component) { - std::string component_type(get_js_class_name(c)); + std::string component_type(get_js_class_name(component)); if (component_type == "entity" || component_type == "id") throw std::runtime_error("Component type '" + component_type + "' not supported : you can't use : id, entity, " + UNKNOWN_COMPONENT_TYPE); if (!_components_arrays.contains(component_type)) _components_arrays.emplace(component_type, SparseArray()); if (!_remove_functions.contains(component_type)) { - _remove_functions.emplace(component_type, [c](Registry ®, Entity const &ent) { - SparseArray &array = reg.get_components(c); + _remove_functions.emplace(component_type, [component](Registry ®, Entity const &ent) { + SparseArray &array = reg.get_components(component); array.erase(ent); }); } - // TODO: rework logger + // TODO: rework logger https://github.com/NanoForge-dev/Engine/issues/104 // if (!_loggers.contains(component_type)) { // _loggers.emplace(component_type, [](Registry const ®, Entity const &ent) { // const auto &array = reg.get_components(); @@ -54,42 +62,77 @@ namespace nfo { return std::any_cast &>(_components_arrays[component_type]); } - SparseArray &get_components(const Component &c) + /** + * Get the SparseArray of a given component type. + * + * @param component An instance of the component type to get. + * @return A reference to the SparseArray holding all components of this type. + * @throws std::runtime_error if the component type is not registered. + */ + SparseArray &get_components(const Component &component) { - const std::string component_type(get_js_class_name(c)); + const std::string component_type(get_js_class_name(component)); if (!_components_arrays.contains(component_type)) - register_component(c); + register_component(component); std::any &components = _components_arrays[component_type]; return std::any_cast &>(components); } - [[nodiscard]] SparseArray const &get_components(const Component &c) const + /** + * Get the SparseArray of a given component type (const version). + * + * @param component An instance of the component type to get. + * @return A const reference to the SparseArray holding all components of this type. + * @throws std::runtime_error if the component type is not registered. + */ + [[nodiscard]] SparseArray const &get_components(const Component &component) const { - const std::string component_type(get_js_class_name(c)); + const std::string component_type(get_js_class_name(component)); if (!_components_arrays.contains(component_type)) throw std::runtime_error(component_type + " array not registered"); const std::any &components = _components_arrays.find(component_type)->second; return std::any_cast &>(components); } - std::optional &get_entity_component(const Entity e, const Component &c) + /** + * Get the component of a given entity. + * + * @param entity The entity to get the component from. + * @param component An instance of the component type to get. + * @return A reference to an optional containing the component if it exists, or std::nullopt otherwise. + * @throws std::runtime_error if the component type is not registered. + */ + std::optional &get_entity_component(const Entity entity, const Component &component) { - const std::string component_type(get_js_class_name(c)); + const std::string component_type(get_js_class_name(component)); if (!_components_arrays.contains(component_type)) - register_component(c); + register_component(component); std::any &components = _components_arrays[component_type]; - return std::any_cast &>(components)[e]; + return std::any_cast &>(components)[entity]; } - [[nodiscard]] std::optional const &get_entity_component(const Entity e, const Component &c) const + /** + * Get the component of a given entity (const version). + * + * @param entity The entity to get the component from. + * @param component An instance of the component type to get. + * @return A const reference to an optional containing the component if it exists, or std::nullopt otherwise. + * @throws std::runtime_error if the component type is not registered. + */ + [[nodiscard]] std::optional const &get_entity_component(const Entity entity, const Component &component) const { - const std::string component_type(get_js_class_name(c)); + const std::string component_type(get_js_class_name(component)); if (!_components_arrays.contains(component_type)) throw std::runtime_error(component_type + " array not registered"); const std::any &components = _components_arrays.find(component_type)->second; - return std::any_cast &>(components)[e]; + return std::any_cast &>(components)[entity]; } + /** + * Spawn a new entity. + * + * @return The newly spawned entity. + */ [[nodiscard]] Entity spawn_entity() { if (!_dead_entities.empty()) { @@ -101,6 +144,13 @@ namespace nfo { return Entity(_next_entity - 1); } + /** + * Get an entity from its index. + * + * @param component_type The index of the entity. + * @return The entity corresponding to the given index. + * @throws std::runtime_error if the index is out of range. + */ Entity entity_from_index(const std::size_t component_type) { if (std::ranges::find(_dead_entities, component_type) != _dead_entities.end() || component_type >= _next_entity) @@ -108,13 +158,21 @@ namespace nfo { return Entity(component_type); } - void kill_entity(Entity const &e) + /** + * Kill an entity, marking it for removal. + * + * @param entity The entity to kill. + */ + void kill_entity(Entity const &entity) { - _dead_entities.push_back(e); + _dead_entities.push_back(entity); for (const std::function &remove_function : std::views::values(_remove_functions)) - remove_function(*this, e); + remove_function(*this, entity); } + /** + * Clear all entities and reset the registry. + */ void clear_entities() { _next_entity = 0; @@ -124,30 +182,53 @@ namespace nfo { _components_arrays.clear(); } - SparseArray::reference_type add_component(Entity const &to, Component &&c) + /** + * Add a component to an entity. + * + * @param entity The entity to add the component to. + * @param component The component to add. + * @return A reference to the added component. + */ + SparseArray::reference_type add_component(Entity const &entity, Component &&component) { - const std::string component_type(get_js_class_name(c)); + const std::string component_type(get_js_class_name(component)); if (!_components_arrays.contains(component_type)) { - register_component(c); + register_component(component); } - return get_components(c).insert_at(to, c); + return get_components(component).insert_at(entity, component); } - void remove_component(Entity const &from, Component &&c) + /** + * Remove a component from an entity. + * + * @param entity The entity to remove the component from. + * @param component The component to remove. + */ + void remove_component(Entity const &entity, Component &&component) { - const std::string component_type(get_js_class_name(c)); + const std::string component_type(get_js_class_name(component)); if (!_components_arrays.contains(component_type)) - register_component(c); + register_component(component); if (_remove_functions.contains(component_type)) - _remove_functions[component_type](*this, from); + _remove_functions[component_type](*this, entity); } + /** + * Add a system to the registry. + * + * @param f The system function to add. + */ template void add_system(Function &&f) { _systems.emplace_back(std::forward(f)); } + /** + * Remove a system from the registry by its index. + * + * @param system_idx The index of the system to remove. + */ void remove_system(const std::size_t system_idx) { if (system_idx >= _systems.size()) @@ -155,11 +236,19 @@ namespace nfo { _systems.erase(_systems.begin() + static_cast(system_idx)); } + /** + * Clear all systems from the registry. + */ void clear_systems() { _systems.clear(); } + /** + * Run all systems with the given context. + * + * @param ctx The context to pass to each system. + */ void run_systems(const emscripten::val &ctx) { std::vector> systems_copy = _systems; @@ -167,6 +256,11 @@ namespace nfo { system(*this, ctx); } + /** + * Log information about an entity. (Costly operation as logging in JS is not memory safe) + * + * @param entity The entity to log information about. + */ void log(const Entity &entity) const { for (const auto &logger : std::views::values(_loggers)) { @@ -175,11 +269,23 @@ namespace nfo { } } + /** + * Get the maximum number of entities that have been spawned. + * + * @return The maximum number of entities. + */ [[nodiscard]] std::size_t max_entities() const { return _next_entity; } + /** + * Get the zipper output for the given components. + * + * @param comps An array of component types to zip. + * @return A ZipperOutput containing the zipped components. + * @throws std::runtime_error if the input is not an array. + */ ZipperOutput get_zipper(const ZipperInput &comps) { if (!comps.isArray()) From f389d1a0580ceb116ef33b7caa1a7d9601b0695e Mon Sep 17 00:00:00 2001 From: MartinFillon Date: Sat, 6 Dec 2025 17:21:10 +0100 Subject: [PATCH 2/9] docs(ecs): setup sphinx for ecs documentation --- packages/ecs-lib/.gitignore | 1 + packages/ecs-lib/docs/Doxyfile | 7 +++++++ packages/ecs-lib/docs/conf.py | 8 ++++++++ packages/ecs-lib/docs/index.rst | 11 +++++++++++ 4 files changed, 27 insertions(+) create mode 100644 packages/ecs-lib/docs/Doxyfile create mode 100644 packages/ecs-lib/docs/conf.py create mode 100644 packages/ecs-lib/docs/index.rst diff --git a/packages/ecs-lib/.gitignore b/packages/ecs-lib/.gitignore index 6542710..56e936f 100644 --- a/packages/ecs-lib/.gitignore +++ b/packages/ecs-lib/.gitignore @@ -274,3 +274,4 @@ lib/index.js lib/libecs.js compile_commands.json emsdk/ +doc_out/ diff --git a/packages/ecs-lib/docs/Doxyfile b/packages/ecs-lib/docs/Doxyfile new file mode 100644 index 0000000..de738a6 --- /dev/null +++ b/packages/ecs-lib/docs/Doxyfile @@ -0,0 +1,7 @@ +GENERATE_XML = YES +GENERATE_HTML = NO +GENERATE_LATEX = NO + +INPUT = ../wasm + +OUTPUT_DIRECTORY = doc_out diff --git a/packages/ecs-lib/docs/conf.py b/packages/ecs-lib/docs/conf.py new file mode 100644 index 0000000..1aa60a6 --- /dev/null +++ b/packages/ecs-lib/docs/conf.py @@ -0,0 +1,8 @@ +# from cgitb import html + +extensions = ["breathe"] + +html_theme = "sphinx_rtd_theme" + +# Breathe configuration +breathe_default_project = "my_project" diff --git a/packages/ecs-lib/docs/index.rst b/packages/ecs-lib/docs/index.rst new file mode 100644 index 0000000..8da3125 --- /dev/null +++ b/packages/ecs-lib/docs/index.rst @@ -0,0 +1,11 @@ +My Project Documentation +========== + +.. toctree:: + :maxdepth: 2 + +C++ classes +----------- + +.. doxygenclass:: nfo::Registry + :members: From a0e47b2b2a859e18f6697ce616e74b89c1755ab3 Mon Sep 17 00:00:00 2001 From: MartinFillon Date: Sun, 7 Dec 2025 11:12:43 +0100 Subject: [PATCH 3/9] docs(ecs): start connecting typescript to sphinx --- docs/Documentation.md | 10 ++++++++++ docs/Registry.md | 1 - packages/ecs-lib/docs/conf.py | 6 +++++- packages/ecs-lib/docs/index.rst | 11 ++++------- packages/ecs-lib/docs/typescript.rst | 8 ++++++++ packages/ecs-lib/docs/wasm.rst | 11 +++++++++++ packages/ecs-lib/src/ecs-library.abstract.ts | 18 ++++++++++++++++++ 7 files changed, 56 insertions(+), 9 deletions(-) create mode 100644 docs/Documentation.md create mode 100644 packages/ecs-lib/docs/typescript.rst create mode 100644 packages/ecs-lib/docs/wasm.rst diff --git a/docs/Documentation.md b/docs/Documentation.md new file mode 100644 index 0000000..6258c87 --- /dev/null +++ b/docs/Documentation.md @@ -0,0 +1,10 @@ +# Documentation + +## Generate Code Documentation + +To generate code documentation you will need to have Sphinx and Breathe installed, and Doxygen. You can install them using pip: + +```bash +pip install sphinx breathe sphinx-rtd-theme sphinx-js +sudo apt install doxygen +``` diff --git a/docs/Registry.md b/docs/Registry.md index af5852c..f3ad730 100644 --- a/docs/Registry.md +++ b/docs/Registry.md @@ -5,7 +5,6 @@ This choice was made to leverage the performance benefits of C++ for managing en Emscripten allows us to compile C++ code into WebAssembly, which can then be used in web applications, providing a bridge between high-performance C++ code and JavaScript. - ## Design Choices This design makes some trade-offs between performance and ease of use. A pure C++ ECS would have been easier to use but having to bind it as us make choices that impact usability. diff --git a/packages/ecs-lib/docs/conf.py b/packages/ecs-lib/docs/conf.py index 1aa60a6..e23714d 100644 --- a/packages/ecs-lib/docs/conf.py +++ b/packages/ecs-lib/docs/conf.py @@ -1,8 +1,12 @@ # from cgitb import html -extensions = ["breathe"] +extensions = ["breathe", "sphinx_js"] html_theme = "sphinx_rtd_theme" +js_language = "typescript" + +js_source_path = "../src/" + # Breathe configuration breathe_default_project = "my_project" diff --git a/packages/ecs-lib/docs/index.rst b/packages/ecs-lib/docs/index.rst index 8da3125..264e899 100644 --- a/packages/ecs-lib/docs/index.rst +++ b/packages/ecs-lib/docs/index.rst @@ -1,11 +1,8 @@ -My Project Documentation -========== +ECS Documentation +================= .. toctree:: :maxdepth: 2 -C++ classes ------------ - -.. doxygenclass:: nfo::Registry - :members: + wasm + typescript diff --git a/packages/ecs-lib/docs/typescript.rst b/packages/ecs-lib/docs/typescript.rst new file mode 100644 index 0000000..e05f361 --- /dev/null +++ b/packages/ecs-lib/docs/typescript.rst @@ -0,0 +1,8 @@ +Typescript +========== + +.. js:autoclass:: AbstractECSLibrary + :members: + +.. js::autoclass:: ECElementDefaults + :members: diff --git a/packages/ecs-lib/docs/wasm.rst b/packages/ecs-lib/docs/wasm.rst new file mode 100644 index 0000000..bd9ea6b --- /dev/null +++ b/packages/ecs-lib/docs/wasm.rst @@ -0,0 +1,11 @@ +C++ classes +----------- + +.. doxygenclass:: nfo::Registry + :members: + +.. doxygenclass:: nfo::Entity + :members: + +.. doxygenclass:: nfo::SparseArray + :members: diff --git a/packages/ecs-lib/src/ecs-library.abstract.ts b/packages/ecs-lib/src/ecs-library.abstract.ts index eed8e97..fa1ebec 100644 --- a/packages/ecs-lib/src/ecs-library.abstract.ts +++ b/packages/ecs-lib/src/ecs-library.abstract.ts @@ -7,6 +7,14 @@ import { import { type MainModule, type Registry } from "../lib/libecs"; +/** + * Abstract class representing an ECS (Entity Component System) library. + * Extends the BaseComponentSystemLibrary to provide ECS-specific functionality. + * Manages a registry of systems and ensures proper initialization before use. + * @abstract + * @class AbstractECSLibrary + * @extends {BaseComponentSystemLibrary} + */ export abstract class AbstractECSLibrary extends BaseComponentSystemLibrary { protected module?: MainModule; protected _registry?: Registry; @@ -22,11 +30,21 @@ export abstract class AbstractECSLibrary extends BaseComponentSystemLibrary { abstract override get __name(): string; + /** + * Runs the ECS systems using the provided context. + * @param ctx - The context to be used for running the systems. + * @returns A promise that resolves when the systems have been run. + */ async __run(ctx: Context): Promise { if (!this._registry) this.throwNotInitializedError(); this._registry.runSystems(ctx); } + /** + * Gets the registry. + * @throws Will throw an error if the library is not initialized. + * @returns The registry. + */ get registry(): Registry { if (!this._registry) this.throwNotInitializedError(); return this._registry; From 9e3b34fae2f5319814b36a2247989610f54eb9a6 Mon Sep 17 00:00:00 2001 From: MartinFillon Date: Wed, 10 Dec 2025 16:51:27 +0100 Subject: [PATCH 4/9] docs(ecs): finish cpp side of documentation --- packages/ecs-lib/docs/Makefile | 12 +++ packages/ecs-lib/docs/conf.py | 9 +- packages/ecs-lib/docs/typescript.rst | 8 +- packages/ecs-lib/wasm/Entity.hpp | 6 ++ packages/ecs-lib/wasm/Registry.hpp | 6 ++ packages/ecs-lib/wasm/SparseArray.hpp | 132 ++++++++++++++++++++++++++ 6 files changed, 163 insertions(+), 10 deletions(-) create mode 100644 packages/ecs-lib/docs/Makefile diff --git a/packages/ecs-lib/docs/Makefile b/packages/ecs-lib/docs/Makefile new file mode 100644 index 0000000..e59c62a --- /dev/null +++ b/packages/ecs-lib/docs/Makefile @@ -0,0 +1,12 @@ +all: sphinx + +doxygen: + doxygen Doxyfile + +sphinx: doxygen + sphinx-build -b html . doc_out/sphinx/ + +clean: + rm -rf doc_out/ + +.PHONY: all doxygen sphinx diff --git a/packages/ecs-lib/docs/conf.py b/packages/ecs-lib/docs/conf.py index e23714d..23a556d 100644 --- a/packages/ecs-lib/docs/conf.py +++ b/packages/ecs-lib/docs/conf.py @@ -1,12 +1,9 @@ # from cgitb import html -extensions = ["breathe", "sphinx_js"] +extensions = ["breathe"] html_theme = "sphinx_rtd_theme" -js_language = "typescript" - -js_source_path = "../src/" - # Breathe configuration -breathe_default_project = "my_project" +breathe_projects = {"ecs-lib": "doc_out/xml"} +breathe_default_project = "ecs-lib" diff --git a/packages/ecs-lib/docs/typescript.rst b/packages/ecs-lib/docs/typescript.rst index e05f361..0405804 100644 --- a/packages/ecs-lib/docs/typescript.rst +++ b/packages/ecs-lib/docs/typescript.rst @@ -1,8 +1,8 @@ Typescript ========== -.. js:autoclass:: AbstractECSLibrary - :members: +.. .. js:autoclass:: AbstractECSLibrary +.. :members: -.. js::autoclass:: ECElementDefaults - :members: +.. .. js::typealias:: ECSElementDefaults +.. :members: diff --git a/packages/ecs-lib/wasm/Entity.hpp b/packages/ecs-lib/wasm/Entity.hpp index 40ed54a..27e2f46 100644 --- a/packages/ecs-lib/wasm/Entity.hpp +++ b/packages/ecs-lib/wasm/Entity.hpp @@ -16,6 +16,12 @@ #include namespace nfo { + /** + ** @brief Represents an entity in the ECS (Entity-Component-System) architecture. + ** + ** This class encapsulates the concept of an entity, which is identified by a unique ID. + ** Entities are used to group components together in the ECS paradigm. + */ class Entity { public: /** diff --git a/packages/ecs-lib/wasm/Registry.hpp b/packages/ecs-lib/wasm/Registry.hpp index 9084bda..c118465 100644 --- a/packages/ecs-lib/wasm/Registry.hpp +++ b/packages/ecs-lib/wasm/Registry.hpp @@ -26,6 +26,12 @@ #include "Utils.hpp" namespace nfo { + /** + ** @brief The main registry class for managing entities and components. + ** + ** This class provides methods to register components, manage entities, + ** add and remove components from entities, and run systems. + */ class Registry { public: /** diff --git a/packages/ecs-lib/wasm/SparseArray.hpp b/packages/ecs-lib/wasm/SparseArray.hpp index 95c57ce..d6d87cc 100644 --- a/packages/ecs-lib/wasm/SparseArray.hpp +++ b/packages/ecs-lib/wasm/SparseArray.hpp @@ -19,6 +19,14 @@ #include namespace nfo { + /** + ** @brief A sparse array implementation that allows for optional components. + ** @tparam Component The type of component to be stored in the sparse array. + ** + ** This class provides a way to store components in a sparse manner, allowing for efficient + ** storage and retrieval of components by their indices. It uses std::optional to represent + ** the presence or absence of a component at a given index. + */ template class SparseArray { public: @@ -31,12 +39,28 @@ namespace nfo { using iterator = typename container::iterator; using const_iterator = typename container::const_iterator; + /** + * @brief Default constructor for SparseArray. + */ SparseArray() = default; + /** + * @brief Copy constructor for SparseArray. + * @param other The SparseArray to copy from. + */ SparseArray(SparseArray const &other) : _data(other._data) {} + /** + * @brief Move constructor for SparseArray. + * @param other The SparseArray to move from. + */ SparseArray(SparseArray &&other) noexcept : _data(std::move(other._data)) {} + /** + * @brief Copy assignment operator for SparseArray. + * @param other The SparseArray to copy from. + * @return Reference to this SparseArray. + */ SparseArray &operator=(SparseArray const &other) { if (this != &other) { @@ -45,6 +69,11 @@ namespace nfo { return *this; } + /** + * @brief Move assignment operator for SparseArray. + * @param other The SparseArray to move from. + * @return Reference to this SparseArray. + */ SparseArray &operator=(SparseArray &&other) noexcept { if (this != &other) { @@ -53,6 +82,11 @@ namespace nfo { return *this; } + /** + * @brief Erase the component at the given index. + * + * @param idx The index of the component to erase. + */ void erase(const size_type &idx) { if (idx < _data.size()) { @@ -60,36 +94,68 @@ namespace nfo { } } + /** + * @brief Get an iterator to the beginning of the sparse array. + * @return An iterator to the beginning of the sparse array. + */ iterator begin() { return _data.begin(); } + /** + * @brief Get a const iterator to the beginning of the sparse array. + * @return A const iterator to the beginning of the sparse array. + */ [[nodiscard]] const_iterator begin() const { return _data.begin(); } + /** + * @brief Get a const iterator to the beginning of the sparse array. + * @return A const iterator to the beginning of the sparse array. + */ [[nodiscard]] const_iterator cbegin() const { return _data.cbegin(); } + /** + * @brief Get an iterator to the end of the sparse array. + * @return An iterator to the end of the sparse array. + */ iterator end() { return _data.end(); } + /** + * @brief Get a const iterator to the end of the sparse array. + * @return A const iterator to the end of the sparse array. + */ [[nodiscard]] const_iterator end() const { return _data.end(); } + /** + * @brief Get a const iterator to the end of the sparse array. + * @return A const iterator to the end of the sparse array. + */ [[nodiscard]] const_iterator cend() const { return _data.cend(); } + /** + * @brief Access the component at the given index. + * + * If the index is out of bounds, the sparse array is resized to accommodate the index. + * + * @param idx The index of the component to access. + * @return A reference to the optional component at the given index. + */ reference_type operator[](size_type idx) { if (idx >= _data.size()) { @@ -98,6 +164,14 @@ namespace nfo { return _data[idx]; } + /** + * @brief Access the component at the given index (const version). + * + * If the index is out of bounds, returns a reference to a null optional. + * + * @param idx The index of the component to access. + * @return A const reference to the optional component at the given index. + */ const_reference_type operator[](size_type idx) const { if (idx >= _data.size()) { @@ -106,31 +180,64 @@ namespace nfo { return _data[idx]; } + /** + * @brief Set the component at the given index. + * + * @param idx The index of the component to set. + * @param value The component value to set. + */ void set(size_type idx, value_type value) { (*this)[idx] = std::move(value); } + /** + * @brief Get the size of the sparse array. + * + * @return The size of the sparse array. + */ [[nodiscard]] size_type size() const { return _data.size(); } + /** + * @brief Resize the sparse array to the given size. + * + * @param size The new size of the sparse array. + */ void resize(size_type size) { _data.resize(size); } + /** + * @brief Clear the sparse array. + */ void clear() { _data.clear(); } + /** + * @brief Check if the sparse array is empty. + * + * @return True if the sparse array is empty, false otherwise. + */ [[nodiscard]] bool empty() const { return _data.empty() || std::ranges::all_of(_data, [](const auto &v) { return !v.has_value(); }); } + /** + * @brief Insert a component at the given index. + * + * If the index is out of bounds, the sparse array is resized to accommodate the index. + * + * @param idx The index at which to insert the component. + * @param value The component value to insert. + * @return A reference to the inserted optional component. + */ reference_type insert_at(size_type idx, const_reference_type value) { if (idx >= _data.size()) { @@ -140,6 +247,15 @@ namespace nfo { return _data[idx]; } + /** + * @brief Insert a component at the given index (move version). + * + * If the index is out of bounds, the sparse array is resized to accommodate the index. + * + * @param idx The index at which to insert the component. + * @param value The component value to insert. + * @return A reference to the inserted optional component. + */ reference_type insert_at(size_type idx, move_reference_type value) { if (idx >= _data.size()) { @@ -149,6 +265,16 @@ namespace nfo { return _data[idx]; } + /** + * @brief Emplace a component at the given index. + * + * If the index is out of bounds, the sparse array is resized to accommodate the index. + * + * @tparam Params The types of the parameters to construct the component. + * @param idx The index at which to emplace the component. + * @param params The parameters to construct the component. + * @return A reference to the emplaced optional component. + */ template reference_type emplace_at(size_type idx, Params &&...params) { @@ -159,6 +285,12 @@ namespace nfo { return _data[idx]; } + /** + * @brief Get the index of the given component value. + * + * @param value The component value to find. + * @return The index of the component value, or size() if not found. + */ [[nodiscard]] size_type get_index(const_reference_type value) const { auto it = std::find(_data.begin(), _data.end(), value); From f4d97c6d8139177bc8a845089e18b6629b6dc36a Mon Sep 17 00:00:00 2001 From: MartinFillon Date: Sat, 3 Jan 2026 11:35:17 +0100 Subject: [PATCH 5/9] docs: setup new doc system --- docs/Documentation.md | 10 ------ docs/Introduction.md | 14 -------- docs/Registry.md | 18 ----------- docs/Writing_Web_Assembly.md | 15 --------- docs/documentation.rst | 7 ++++ docs/how_to_use.rst | 21 ++++++++++++ docs/index.rst | 12 +++++++ docs/registry/index.rst | 44 ++++++++++++++++++++++++++ docs/registry/writing_web_assembly.rst | 35 ++++++++++++++++++++ 9 files changed, 119 insertions(+), 57 deletions(-) delete mode 100644 docs/Documentation.md delete mode 100644 docs/Introduction.md delete mode 100644 docs/Registry.md delete mode 100644 docs/Writing_Web_Assembly.md create mode 100644 docs/documentation.rst create mode 100644 docs/how_to_use.rst create mode 100644 docs/index.rst create mode 100644 docs/registry/index.rst create mode 100644 docs/registry/writing_web_assembly.rst diff --git a/docs/Documentation.md b/docs/Documentation.md deleted file mode 100644 index 6258c87..0000000 --- a/docs/Documentation.md +++ /dev/null @@ -1,10 +0,0 @@ -# Documentation - -## Generate Code Documentation - -To generate code documentation you will need to have Sphinx and Breathe installed, and Doxygen. You can install them using pip: - -```bash -pip install sphinx breathe sphinx-rtd-theme sphinx-js -sudo apt install doxygen -``` diff --git a/docs/Introduction.md b/docs/Introduction.md deleted file mode 100644 index aa34ac7..0000000 --- a/docs/Introduction.md +++ /dev/null @@ -1,14 +0,0 @@ -# Introduction to using the Engine - -Whether you work on this engine as a devlopper or you wanna use this engine you gonna want to have a test project. -This is a walkthrough on how to setup a basic project - -## As a devlopper on the engine - -As a devlopper you want to be able to use your changes in your project. -Therefore it is recommended to use the provided template in the [example](https://github.com/NanoForge-dev/Engine/tree/main/example/template) - -## As a user - -As a user you can either use the template and change the dependencies location. -Or you can create a project and add the nanoforge dependencies. Note that it is recommended to use bun as a package manager. diff --git a/docs/Registry.md b/docs/Registry.md deleted file mode 100644 index f3ad730..0000000 --- a/docs/Registry.md +++ /dev/null @@ -1,18 +0,0 @@ -# Registry - -The registry class is written in C++ and exposed to WebAssembly using Emscripten. -This choice was made to leverage the performance benefits of C++ for managing entities and components in an ECS architecture. -Emscripten allows us to compile C++ code into WebAssembly, which can then be -used in web applications, providing a bridge between high-performance C++ code and JavaScript. - -## Design Choices - -This design makes some trade-offs between performance and ease of use. A pure C++ ECS would have been easier to use but having to bind it as us make choices that impact usability. - -### Const Correctness - -In a regular C++ ECS, const correctness is a given, but when exposing C++ to WebAssembly, as in C++ we can force constant of return values. But in WebAssembly, the concept of const correctness does not directly translate to JavaScript. Therefore, methods that would typically return const references in C++ may return non-const references or copies when exposed to WebAssembly. We deciced to keep the const correctness in the C++ code to maintain clarity and intent within the C++ domain, even if it doesn't fully carry over to the WebAssembly interface. - -### Error Handling - -Any thrown exceptions in C++ will result in a runtime error in JavaScript. The problem with this approach is that the error messages may not be as descriptive or user-friendly as native JavaScript errors. As every error thrown in C++ will be caught as a generic runtime error in JavaScript, it can make debugging more challenging. To mitigate this, we recommend thorough testing and validation within the C++ code to catch potential issues before they propagate to the WebAssembly layer. diff --git a/docs/Writing_Web_Assembly.md b/docs/Writing_Web_Assembly.md deleted file mode 100644 index c1f6579..0000000 --- a/docs/Writing_Web_Assembly.md +++ /dev/null @@ -1,15 +0,0 @@ -# Writing Web Assembly - -## Code Splitting - -When writing Web Assembly modules, it's important to consider code splitting for readability and maintainability. We try to split binding and code logic into separate files where possible. This helps keep the codebase organized and makes it easier to navigate. - -For example, in the ECS package, the binding logic is in `.cpp` files, while the core logic resides in `.hpp` files. This separation allows developers to focus on either the binding or the logic without being overwhelmed by both at the same time. - -## Documentation - -When documenting Web Assembly modules, we follow a similar approach to C++ documentation. We use Doxygen-style comments to provide clear and concise explanations of classes, methods, and parameters. This documentation is crucial for developers who will be using or maintaining the Web Assembly modules, as it provides necessary context and usage information. - -## Logging - -Logging in Web Assembly is costly memory-wise due to the interaction between C++ and JavaScript. Therefore, we recommend to log from the JavaScript side whenever possible. If logging from C++ is necessary, be aware of the potential performance implications and memory leaks. Web assembly vm is memory limited, so excessive logging will lead to out-of-memory errors. diff --git a/docs/documentation.rst b/docs/documentation.rst new file mode 100644 index 0000000..db4f625 --- /dev/null +++ b/docs/documentation.rst @@ -0,0 +1,7 @@ +Documentation +============= + +The documentation for the engine is seperated between the different libraries of the engine. +Then everything is packed up and put into this site. The documentation is handled on the engine repository and then automatically pushed. + +This documentation is written in restructured text in order for it to be easier to operate with. We use sphinx to generate the relevant generated documentation. diff --git a/docs/how_to_use.rst b/docs/how_to_use.rst new file mode 100644 index 0000000..97c1034 --- /dev/null +++ b/docs/how_to_use.rst @@ -0,0 +1,21 @@ +Introduction to using the Engine +================================ + +Whether you work on this engine as a devlopper or you wanna use this +engine you gonna want to have a test project. This is a walkthrough on +how to setup a basic project + +As a devlopper on the engine +---------------------------- + +As a devlopper you want to be able to use your changes in your project. +Therefore it is recommended to use the provided template in the +`example `__ + +As a user +--------- + +As a user you can either use the template and change the dependencies +location. Or you can create a project and add the nanoforge +dependencies. Note that it is recommended to use bun as a package +manager. diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..12e4713 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,12 @@ +Engine +====== + +.. toctree:: + :maxdepth: 2 + + registry + documentation.rst + how_to_use.rst + +In this doc you will find both the how to use and why use this engine as well as its library. +To understand how to use this engine please refer to :doc:`/how_to_use` diff --git a/docs/registry/index.rst b/docs/registry/index.rst new file mode 100644 index 0000000..e642ee1 --- /dev/null +++ b/docs/registry/index.rst @@ -0,0 +1,44 @@ +Registry +======== + +.. toctree:: + :maxdepth: 2 + + writing_web_assembly.rst + +The registry class is written in C++ and exposed to WebAssembly using +Emscripten. This choice was made to leverage the performance benefits of +C++ for managing entities and components in an ECS architecture. +Emscripten allows us to compile C++ code into WebAssembly, which can +then be used in web applications, providing a bridge between +high-performance C++ code and JavaScript. + +Design Choices +-------------- + +This design makes some trade-offs between performance and ease of use. A +pure C++ ECS would have been easier to use but having to bind it as us +make choices that impact usability. + +Const Correctness +~~~~~~~~~~~~~~~~~ + +In a regular C++ ECS, const correctness is a given, but when exposing +C++ to WebAssembly, as in C++ we can force constant of return values. +But in WebAssembly, the concept of const correctness does not directly +translate to JavaScript. Therefore, methods that would typically return +const references in C++ may return non-const references or copies when +exposed to WebAssembly. We deciced to keep the const correctness in the +C++ code to maintain clarity and intent within the C++ domain, even if +it doesn't fully carry over to the WebAssembly interface. + +Error Handling +~~~~~~~~~~~~~~ + +Any thrown exceptions in C++ will result in a runtime error in +JavaScript. The problem with this approach is that the error messages +may not be as descriptive or user-friendly as native JavaScript errors. +As every error thrown in C++ will be caught as a generic runtime error +in JavaScript, it can make debugging more challenging. To mitigate this, +we recommend thorough testing and validation within the C++ code to +catch potential issues before they propagate to the WebAssembly layer. diff --git a/docs/registry/writing_web_assembly.rst b/docs/registry/writing_web_assembly.rst new file mode 100644 index 0000000..7ad7583 --- /dev/null +++ b/docs/registry/writing_web_assembly.rst @@ -0,0 +1,35 @@ +Writing Web Assembly +==================== + +Code Splitting +-------------- + +When writing Web Assembly modules, it's important to consider code +splitting for readability and maintainability. We try to split binding +and code logic into separate files where possible. This helps keep the +codebase organized and makes it easier to navigate. + +For example, in the ECS package, the binding logic is in ``.cpp`` files, +while the core logic resides in ``.hpp`` files. This separation allows +developers to focus on either the binding or the logic without being +overwhelmed by both at the same time. + +Documentation +------------- + +When documenting Web Assembly modules, we follow a similar approach to +C++ documentation. We use Doxygen-style comments to provide clear and +concise explanations of classes, methods, and parameters. This +documentation is crucial for developers who will be using or maintaining +the Web Assembly modules, as it provides necessary context and usage +information. + +Logging +------- + +Logging in Web Assembly is costly memory-wise due to the interaction +between C++ and JavaScript. Therefore, we recommend to log from the +JavaScript side whenever possible. If logging from C++ is necessary, be +aware of the potential performance implications and memory leaks. Web +assembly vm is memory limited, so excessive logging will lead to +out-of-memory errors. From fb1f30e123fb081c19fce31e9b7fa2dd745ec38c Mon Sep 17 00:00:00 2001 From: MartinFillon Date: Sat, 3 Jan 2026 11:40:33 +0100 Subject: [PATCH 6/9] docs(actions): setup push-docs actions to synchronize documentation --- .github/workflows/push-docs.yml | 37 +++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/push-docs.yml diff --git a/.github/workflows/push-docs.yml b/.github/workflows/push-docs.yml new file mode 100644 index 0000000..4fe8c77 --- /dev/null +++ b/.github/workflows/push-docs.yml @@ -0,0 +1,37 @@ +name: synchronize-docs + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + synchronize: + runs-on: ubuntu-latest + steps: + - name: Checkout engine + uses: actions/checkout@v5 + with: + path: engine + + - name: Checkout docs + uses: actions/checkout@v5 + with: + path: docs + repository: nanoforge-dev/docs + token: ${{ secrets.ACTIONS_KEY }} + + - name: setup git + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "username@users.noreply.github.com" + + - name: synchronize docs + run: | + mkdir -p docs/engine + cp engine/docs/. -r docs/engine + cd docs + git add . + git commit -m "chore(engine): updating docs" + git push origin main From c97db5d2b0fa169045806d4658a1b4d0fbee4506 Mon Sep 17 00:00:00 2001 From: MartinFillon Date: Sat, 3 Jan 2026 11:51:37 +0100 Subject: [PATCH 7/9] docs: setup auto push of generated documentation for ecs --- .github/workflows/push-docs.yml | 14 ++++++++++++++ README.md | 6 ++++++ docs/.gitignore | 1 + packages/ecs-lib/.gitignore | 2 +- packages/ecs-lib/docs/Doxyfile | 2 +- packages/ecs-lib/docs/Makefile | 12 ------------ packages/ecs-lib/docs/conf.py | 9 --------- 7 files changed, 23 insertions(+), 23 deletions(-) create mode 100644 docs/.gitignore delete mode 100644 packages/ecs-lib/docs/Makefile delete mode 100644 packages/ecs-lib/docs/conf.py diff --git a/.github/workflows/push-docs.yml b/.github/workflows/push-docs.yml index 4fe8c77..9e539c2 100644 --- a/.github/workflows/push-docs.yml +++ b/.github/workflows/push-docs.yml @@ -4,6 +4,12 @@ on: push: branches: - main + # paths: + # - "*.rst" + # - "Doxyfile" + # - "ecs-lib/" + # - "ecs-server/" + # - "ecs-client/" workflow_dispatch: jobs: @@ -27,6 +33,14 @@ jobs: git config --global user.name "github-actions[bot]" git config --global user.email "username@users.noreply.github.com" + - name: setup registry code documentation + run: | + apt install doxygen -y + cd engine/packages/ecs-lib/docs + doxygen Doxyfile + cd - + cp engine/packages/ecs-lib/docs engine/docs/registry/api + - name: synchronize docs run: | mkdir -p docs/engine diff --git a/README.md b/README.md index 83a9597..05b4065 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![Nanoforge Documentation](https://github.com/NanoForge-dev/docs/actions/workflows/deploy.yml/badge.svg)](https://github.com/NanoForge-dev/docs/actions/workflows/deploy.yml) + # Engine This repository contains the full engine for NanoForge. @@ -20,6 +22,10 @@ This is the full nanoforge engine including all the default libraries. In order to manage this project we use (pnpm)[https://pnpm.io/] +## Documentation + +The full documentation can be found at: [https://nanoforge-dev.github.io/docs/engine](https://nanoforge-dev.github.io/docs/engine) + ## Installing dependencies To install dependencies run: diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..cef6e7b --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +Doxyfile \ No newline at end of file diff --git a/packages/ecs-lib/.gitignore b/packages/ecs-lib/.gitignore index 56e936f..82ecd49 100644 --- a/packages/ecs-lib/.gitignore +++ b/packages/ecs-lib/.gitignore @@ -274,4 +274,4 @@ lib/index.js lib/libecs.js compile_commands.json emsdk/ -doc_out/ +docs/xml diff --git a/packages/ecs-lib/docs/Doxyfile b/packages/ecs-lib/docs/Doxyfile index de738a6..ac94351 100644 --- a/packages/ecs-lib/docs/Doxyfile +++ b/packages/ecs-lib/docs/Doxyfile @@ -4,4 +4,4 @@ GENERATE_LATEX = NO INPUT = ../wasm -OUTPUT_DIRECTORY = doc_out +OUTPUT_DIRECTORY = . diff --git a/packages/ecs-lib/docs/Makefile b/packages/ecs-lib/docs/Makefile deleted file mode 100644 index e59c62a..0000000 --- a/packages/ecs-lib/docs/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -all: sphinx - -doxygen: - doxygen Doxyfile - -sphinx: doxygen - sphinx-build -b html . doc_out/sphinx/ - -clean: - rm -rf doc_out/ - -.PHONY: all doxygen sphinx diff --git a/packages/ecs-lib/docs/conf.py b/packages/ecs-lib/docs/conf.py deleted file mode 100644 index 23a556d..0000000 --- a/packages/ecs-lib/docs/conf.py +++ /dev/null @@ -1,9 +0,0 @@ -# from cgitb import html - -extensions = ["breathe"] - -html_theme = "sphinx_rtd_theme" - -# Breathe configuration -breathe_projects = {"ecs-lib": "doc_out/xml"} -breathe_default_project = "ecs-lib" From 38f4e4fed34b47cc5de207ad841d88d2ca10cf65 Mon Sep 17 00:00:00 2001 From: MartinFillon Date: Tue, 6 Jan 2026 15:36:36 +0100 Subject: [PATCH 8/9] docs(usage): replace template with cli mention and delete template example --- docs/how_to_use.rst | 3 +- example/template/.gitignore | 225 ------------------------------ example/template/.nvmrc | 1 - example/template/.prettierignore | 5 - example/template/.prettierrc | 11 -- example/template/README.md | 31 ---- example/template/build.sh | 5 - example/template/eslint.config.js | 44 ------ example/template/package.json | 77 ---------- example/template/run.sh | 6 - example/template/src/index.ts | 16 --- example/template/tsconfig.json | 14 -- 12 files changed, 1 insertion(+), 437 deletions(-) delete mode 100644 example/template/.gitignore delete mode 100644 example/template/.nvmrc delete mode 100644 example/template/.prettierignore delete mode 100644 example/template/.prettierrc delete mode 100644 example/template/README.md delete mode 100755 example/template/build.sh delete mode 100644 example/template/eslint.config.js delete mode 100644 example/template/package.json delete mode 100755 example/template/run.sh delete mode 100644 example/template/src/index.ts delete mode 100644 example/template/tsconfig.json diff --git a/docs/how_to_use.rst b/docs/how_to_use.rst index 97c1034..68beebb 100644 --- a/docs/how_to_use.rst +++ b/docs/how_to_use.rst @@ -9,8 +9,7 @@ As a devlopper on the engine ---------------------------- As a devlopper you want to be able to use your changes in your project. -Therefore it is recommended to use the provided template in the -`example `__ +Therefore it is recommended to use the provided `cli `__ As a user --------- diff --git a/example/template/.gitignore b/example/template/.gitignore deleted file mode 100644 index 6162e42..0000000 --- a/example/template/.gitignore +++ /dev/null @@ -1,225 +0,0 @@ -### VisualStudioCode template -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -!.vscode/*.code-snippets - -# Local History for Visual Studio Code -.history/ - -# Built Visual Studio Code Extensions -*.vsix - -### JetBrains template -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -# AWS User-specific -.idea/**/aws.xml - -# Generated files -.idea/**/contentModel.xml - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr - -# CMake -cmake-build-*/ - -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# File-based project format -*.iws - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# SonarLint plugin -.idea/sonarlint/ - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# Editor-based Rest Client -.idea/httpRequests - -# Android studio 3.1+ serialized cache file -.idea/caches/build_file_checksums.ser - -### Node template -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional stylelint cache -.stylelintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variable files -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# vuepress v2.x temp and cache directory -.temp -.cache - -# Docusaurus cache and generated files -.docusaurus - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* - diff --git a/example/template/.nvmrc b/example/template/.nvmrc deleted file mode 100644 index c519bf5..0000000 --- a/example/template/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -v24.11.0 diff --git a/example/template/.prettierignore b/example/template/.prettierignore deleted file mode 100644 index e77da01..0000000 --- a/example/template/.prettierignore +++ /dev/null @@ -1,5 +0,0 @@ -# Ignore files for PNPM, NPM and YARN -pnpm-lock.yaml -package-lock.json -yarn.lock -bun.lock diff --git a/example/template/.prettierrc b/example/template/.prettierrc deleted file mode 100644 index d5f635c..0000000 --- a/example/template/.prettierrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "plugins": ["@trivago/prettier-plugin-sort-imports"], - "importOrderSeparation": true, - "importOrderSortSpecifiers": true, - "importOrderParserPlugins": ["typescript", "decorators-legacy"], - "importOrder": ["^~/(.*)$", "^[./]"], - "useTabs": false, - "singleQuote": false, - "trailingComma": "all", - "printWidth": 100 -} diff --git a/example/template/README.md b/example/template/README.md deleted file mode 100644 index abd9ad3..0000000 --- a/example/template/README.md +++ /dev/null @@ -1,31 +0,0 @@ -## setup.sh - -Allow you init your game - -```shell -./setup.sh -``` - -## update.sh - -Allow you to update your lib - -```shell -./update.sh -``` - -## build.sh - -Allow you to build project and copy it to the loader - -```shell -./build.sh Loader -``` - -## run.sh - -Allow you to build project and copy it to the loader, and then run the loader (Ctrl + C to stop it) - -```shell -./run.sh Loader -``` \ No newline at end of file diff --git a/example/template/build.sh b/example/template/build.sh deleted file mode 100755 index b886e83..0000000 --- a/example/template/build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -bun run build -mkdir -p ../../../${1}/apps/server/public/game -cp dist/* ../../../${1}/apps/server/public/game diff --git a/example/template/eslint.config.js b/example/template/eslint.config.js deleted file mode 100644 index efc80f1..0000000 --- a/example/template/eslint.config.js +++ /dev/null @@ -1,44 +0,0 @@ -import pluginJs from "@eslint/js"; -import eslintConfigPrettier from "eslint-config-prettier"; -import globals from "globals"; -import tseslint from "typescript-eslint"; - -export default [ - { files: ["src/**/*.{js,mjs,cjs,ts}"] }, - { languageOptions: { globals: globals.node } }, - - pluginJs.configs.recommended, - ...tseslint.configs.recommended, - ...tseslint.configs.strict, - eslintConfigPrettier, - { - rules: { - "@typescript-eslint/consistent-type-imports": [ - "error", - { - disallowTypeAnnotations: true, - fixStyle: "inline-type-imports", - prefer: "type-imports", - }, - ], - "@typescript-eslint/no-extraneous-class": "off", - "@typescript-eslint/no-empty-object-type": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/ban-ts-comment": "off", - "@typescript-eslint/member-ordering": [ - "error", - { - default: [ - "static-field", - "field", - "public-static-method", - "constructor", - "method", - "protected-method", - "private-method", - ], - }, - ], - }, - }, -]; diff --git a/example/template/package.json b/example/template/package.json deleted file mode 100644 index 927cde9..0000000 --- a/example/template/package.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "name": "nanoforge-example-template", - "version": "0.0.0", - "description": "NanoForge Loader - Web", - "homepage": "https://github.com/NanoForge-dev/Loader#readme", - "license": "MIT", - "contributors": [ - "Bill", - "Exelo", - "Fexkoser", - "Tchips" - ], - "funding": { - "type": "individual", - "url": "" - }, - "type": "module", - "module": "src/index.ts", - "browser": true, - "repository": { - "type": "git", - "url": "git+https://github.com/NanoForge-dev/Loader.git", - "directory": "apps/web" - }, - "private": true, - "scripts": { - "setup": "bun i", - "build": "bun run clean && bun run build:raw", - "build:raw": "bun build src/index.ts --outdir dist --asset-naming \"[name].[ext]\"", - "clean": "rm -rf dist", - "lint": "eslint . && prettier --check . '!.cloud/**'", - "format": "eslint . --fix && prettier --write . '!.cloud/**'", - "lint-staged": "lint-staged" - }, - "dependencies": { - "@nanoforge-dev/asset-manager": "workspace:^", - "@nanoforge-dev/common": "workspace:^", - "@nanoforge-dev/config": "workspace:^", - "@nanoforge-dev/core": "workspace:^", - "@nanoforge-dev/ecs-client": "workspace:^", - "@nanoforge-dev/graphics-2d": "workspace:^", - "@nanoforge-dev/input": "workspace:^", - "@nanoforge-dev/sound": "workspace:^" - }, - "devDependencies": { - "@eslint/js": "^9.39.1", - "@trivago/prettier-plugin-sort-imports": "^6.0.0", - "@types/bun": "latest", - "eslint": "^9.39.1", - "eslint-config-prettier": "^10.1.8", - "eslint-plugin-format": "^1.0.2", - "eslint-plugin-prettier": "^5.5.4", - "globals": "^16.5.0", - "prettier": "^3.6.2", - "typescript-eslint": "^8.47.0" - }, - "peerDependencies": { - "typescript": "^5" - }, - "engines": { - "node": "24.11.0", - "bun": "1.3.2" - }, - "packageManager": "bun@1.3.2", - "lint-staged": { - "**/*.{js,ts,html,css}": [ - "eslint --fix", - "prettier --write" - ] - }, - "workspaces": [ - ".", - "../../packages/*", - "../../libs/*", - "../../utils/*" - ] -} diff --git a/example/template/run.sh b/example/template/run.sh deleted file mode 100755 index 73745c1..0000000 --- a/example/template/run.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -./build.sh ${1} -cd ../../../${1}/apps - -bun run dev diff --git a/example/template/src/index.ts b/example/template/src/index.ts deleted file mode 100644 index 39433bc..0000000 --- a/example/template/src/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { AssetManagerLibrary } from "@nanoforge-dev/asset-manager"; -import { type IRunOptions } from "@nanoforge-dev/common"; -import { NanoforgeFactory } from "@nanoforge-dev/core"; -import { ECSClientLibrary } from "@nanoforge-dev/ecs-client"; -import { Graphics2DLibrary } from "@nanoforge-dev/graphics-2d"; - -export const app = NanoforgeFactory.createClient(); - -export const main = async (options: IRunOptions) => { - app.useGraphics(new Graphics2DLibrary()); - app.useAssetManager(new AssetManagerLibrary()); - app.useComponentSystem(new ECSClientLibrary()); - - await app.init(options); - app.run(); -}; diff --git a/example/template/tsconfig.json b/example/template/tsconfig.json deleted file mode 100644 index d84e1b8..0000000 --- a/example/template/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "target": "es2023", - "module": "commonjs", - "rootDir": "./src", - "outDir": "./dist", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true, - "paths": { - } - } -} From 01f213a5366271c75a25de48b0b9307fc8a7550f Mon Sep 17 00:00:00 2001 From: Exelo Date: Tue, 6 Jan 2026 16:57:33 +0100 Subject: [PATCH 9/9] ci: update push-docs workflow to monitor specific documentation paths --- .github/workflows/push-docs.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/push-docs.yml b/.github/workflows/push-docs.yml index 9e539c2..1493b04 100644 --- a/.github/workflows/push-docs.yml +++ b/.github/workflows/push-docs.yml @@ -4,12 +4,10 @@ on: push: branches: - main - # paths: - # - "*.rst" - # - "Doxyfile" - # - "ecs-lib/" - # - "ecs-server/" - # - "ecs-client/" + paths: + - "docs/**" + - "packages/ecs-lib/docs/**" + - "packages/ecs-lib/wasm/**" workflow_dispatch: jobs: