diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml
index 9c3b9ec8..bae3ae62 100644
--- a/.github/workflows/pre-release.yml
+++ b/.github/workflows/pre-release.yml
@@ -37,7 +37,7 @@ jobs:
packages: "@nanoforge-dev/asset-manager,@nanoforge-dev/common,@nanoforge-dev/config,@nanoforge-dev/core,@nanoforge-dev/core-editor,@nanoforge-dev/ecs-client,@nanoforge-dev/ecs-lib,@nanoforge-dev/ecs-server,@nanoforge-dev/graphics-2d,@nanoforge-dev/input,@nanoforge-dev/music,@nanoforge-dev/network-client,@nanoforge-dev/network-server,@nanoforge-dev/sound"
version: ${{ inputs.version }}
branch-format: "releases/nanoforge@{version}"
- commit-format: "chore: release nanoforge@{version}"
+ commit-format: "chore: release @nanoforge-dev/engine@{version}"
dry: ${{ inputs.dry_run }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 964c1c2c..a86f6ca6 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -94,3 +94,4 @@ jobs:
repository: engine
category: engine
references: true
+ references-path: docs/references
diff --git a/.idea/[NanoForge] Engine.iml b/.idea/[NanoForge] Engine.iml
index 85b6fa8e..fc5ad77e 100644
--- a/.idea/[NanoForge] Engine.iml
+++ b/.idea/[NanoForge] Engine.iml
@@ -10,6 +10,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
index 38e317fb..68591eef 100644
--- a/README.md
+++ b/README.md
@@ -6,9 +6,8 @@
-
-
+
diff --git a/docs.json b/docs.json
index 4edae43e..e69de29b 100644
--- a/docs.json
+++ b/docs.json
@@ -1,405 +0,0 @@
-{
- "documentation": {
- "group": "Engine",
- "pages": [
- "docs/engine/api/asset-manager/asset-manager/AssetManagerLibrary/getAsset",
- "docs/engine/api/asset-manager/asset-manager/AssetManagerLibrary/__init",
- "docs/engine/api/asset-manager/asset-manager/AssetManagerLibrary/__name",
- "docs/engine/api/asset-manager/asset-manager/AssetManagerLibrary",
- "docs/engine/api/asset-manager/asset-manager",
- "docs/engine/api/asset-manager/index",
- "docs/engine/api/common/common/ApplicationContext/_delta",
- "docs/engine/api/common/common/ApplicationContext/delta",
- "docs/engine/api/common/common/ApplicationContext/isRunning",
- "docs/engine/api/common/common/ApplicationContext/muteSoundLibraries",
- "docs/engine/api/common/common/ApplicationContext/setIsRunning",
- "docs/engine/api/common/common/ApplicationContext",
- "docs/engine/api/common/common/ASSET_MANAGER_LIBRARY",
- "docs/engine/api/common/common/BaseAssetManagerLibrary/getAsset",
- "docs/engine/api/common/common/BaseAssetManagerLibrary/__init",
- "docs/engine/api/common/common/BaseAssetManagerLibrary",
- "docs/engine/api/common/common/BaseComponentSystemLibrary/__run",
- "docs/engine/api/common/common/BaseComponentSystemLibrary",
- "docs/engine/api/common/common/BaseGraphicsLibrary/__run",
- "docs/engine/api/common/common/BaseGraphicsLibrary",
- "docs/engine/api/common/common/BaseInputLibrary",
- "docs/engine/api/common/common/BaseMusicLibrary/__init",
- "docs/engine/api/common/common/BaseMusicLibrary/mute",
- "docs/engine/api/common/common/BaseMusicLibrary/play",
- "docs/engine/api/common/common/BaseMusicLibrary",
- "docs/engine/api/common/common/BaseNetworkLibrary",
- "docs/engine/api/common/common/BaseSoundLibrary/__init",
- "docs/engine/api/common/common/BaseSoundLibrary/mute",
- "docs/engine/api/common/common/BaseSoundLibrary/play",
- "docs/engine/api/common/common/BaseSoundLibrary",
- "docs/engine/api/common/common/ClearContext",
- "docs/engine/api/common/common/ClientLibraryManager/constructor",
- "docs/engine/api/common/common/ClientLibraryManager/getAssetManager",
- "docs/engine/api/common/common/ClientLibraryManager/getComponentSystem",
- "docs/engine/api/common/common/ClientLibraryManager/getGraphics",
- "docs/engine/api/common/common/ClientLibraryManager/getInput",
- "docs/engine/api/common/common/ClientLibraryManager/get",
- "docs/engine/api/common/common/ClientLibraryManager/getMusic",
- "docs/engine/api/common/common/ClientLibraryManager/getNetwork",
- "docs/engine/api/common/common/ClientLibraryManager/getSound",
- "docs/engine/api/common/common/ClientLibraryManager",
- "docs/engine/api/common/common/COMPONENT_SYSTEM_LIBRARY",
- "docs/engine/api/common/common/Context/app",
- "docs/engine/api/common/common/Context/constructor",
- "docs/engine/api/common/common/Context/libs",
- "docs/engine/api/common/common/Context",
- "docs/engine/api/common/common/DefaultLibrariesEnum",
- "docs/engine/api/common/common/ExecutionContext",
- "docs/engine/api/common/common/GRAPHICS_LIBRARY",
- "docs/engine/api/common/common/IAssetManagerLibrary/getAsset",
- "docs/engine/api/common/common/IAssetManagerLibrary",
- "docs/engine/api/common/common/IComponentSystemLibrary",
- "docs/engine/api/common/common/IConfigRegistry/registerConfig",
- "docs/engine/api/common/common/IConfigRegistry",
- "docs/engine/api/common/common/IExposedLibrary",
- "docs/engine/api/common/common/IGraphicsLibrary",
- "docs/engine/api/common/common/IInputLibrary",
- "docs/engine/api/common/common/ILibrary/__clear",
- "docs/engine/api/common/common/ILibrary/__init",
- "docs/engine/api/common/common/ILibrary/__name",
- "docs/engine/api/common/common/ILibrary/__relationship",
- "docs/engine/api/common/common/ILibrary",
- "docs/engine/api/common/common/IMusicLibrary",
- "docs/engine/api/common/common/IMutableLibrary/mute",
- "docs/engine/api/common/common/IMutableLibrary",
- "docs/engine/api/common/common/INetworkLibrary",
- "docs/engine/api/common/common/InitContext/config",
- "docs/engine/api/common/common/InitContext/constructor",
- "docs/engine/api/common/common/InitContext/container",
- "docs/engine/api/common/common/InitContext/env",
- "docs/engine/api/common/common/InitContext/files",
- "docs/engine/api/common/common/InitContext",
- "docs/engine/api/common/common/INPUT_LIBRARY",
- "docs/engine/api/common/common/IRunClientOptions/container",
- "docs/engine/api/common/common/IRunClientOptions/env",
- "docs/engine/api/common/common/IRunClientOptions/files",
- "docs/engine/api/common/common/IRunClientOptions",
- "docs/engine/api/common/common/IRunnerLibrary/__run",
- "docs/engine/api/common/common/IRunnerLibrary",
- "docs/engine/api/common/common/IRunOptions",
- "docs/engine/api/common/common/IRunServerOptions/env",
- "docs/engine/api/common/common/IRunServerOptions/files",
- "docs/engine/api/common/common/IRunServerOptions",
- "docs/engine/api/common/common/ISoundLibrary",
- "docs/engine/api/common/common/LibraryContext/_status",
- "docs/engine/api/common/common/LibraryContext/status",
- "docs/engine/api/common/common/LibraryContext",
- "docs/engine/api/common/common/LibraryHandle/constructor",
- "docs/engine/api/common/common/LibraryHandle/context",
- "docs/engine/api/common/common/LibraryHandle/library",
- "docs/engine/api/common/common/LibraryHandle/symbol",
- "docs/engine/api/common/common/LibraryHandle",
- "docs/engine/api/common/common/LibraryManager/constructor",
- "docs/engine/api/common/common/LibraryManager/getAssetManager",
- "docs/engine/api/common/common/LibraryManager/getComponentSystem",
- "docs/engine/api/common/common/LibraryManager/getGraphics",
- "docs/engine/api/common/common/LibraryManager/getInput",
- "docs/engine/api/common/common/LibraryManager/getMusic",
- "docs/engine/api/common/common/LibraryManager/getNetwork",
- "docs/engine/api/common/common/LibraryManager/getSound",
- "docs/engine/api/common/common/LibraryManager",
- "docs/engine/api/common/common/LibraryStatusEnum",
- "docs/engine/api/common/common/MUSIC_LIBRARY",
- "docs/engine/api/common/common/NETWORK_LIBRARY",
- "docs/engine/api/common/common/NfConfigException/code",
- "docs/engine/api/common/common/NfConfigException/constructor",
- "docs/engine/api/common/common/NfConfigException",
- "docs/engine/api/common/common/NfFetchException/code",
- "docs/engine/api/common/common/NfFetchException/constructor",
- "docs/engine/api/common/common/NfFetchException",
- "docs/engine/api/common/common/NfFile/arrayBuffer",
- "docs/engine/api/common/common/NfFile/blob",
- "docs/engine/api/common/common/NfFile/bytes",
- "docs/engine/api/common/common/NfFile/constructor",
- "docs/engine/api/common/common/NfFile/formData",
- "docs/engine/api/common/common/NfFile/json",
- "docs/engine/api/common/common/NfFile/path",
- "docs/engine/api/common/common/NfFile/text",
- "docs/engine/api/common/common/NfFile",
- "docs/engine/api/common/common/NfNotFound/code",
- "docs/engine/api/common/common/NfNotFound/constructor",
- "docs/engine/api/common/common/NfNotFound",
- "docs/engine/api/common/common/NfNotInitializedException/code",
- "docs/engine/api/common/common/NfNotInitializedException/constructor",
- "docs/engine/api/common/common/NfNotInitializedException",
- "docs/engine/api/common/common/SOUND_LIBRARY",
- "docs/engine/api/common/common",
- "docs/engine/api/common/index",
- "docs/engine/api/config/config/Default",
- "docs/engine/api/config/config/IsIpOrFQDN",
- "docs/engine/api/config/config/TransformToBoolean",
- "docs/engine/api/config/config",
- "docs/engine/api/config/index",
- "docs/engine/api/core/core/NanoforgeClient/useGraphics",
- "docs/engine/api/core/core/NanoforgeClient/useInput",
- "docs/engine/api/core/core/NanoforgeClient/useSound",
- "docs/engine/api/core/core/NanoforgeClient",
- "docs/engine/api/core/core/NanoforgeFactory",
- "docs/engine/api/core/core/NanoforgeServer",
- "docs/engine/api/core/core",
- "docs/engine/api/core/index",
- "docs/engine/api/core-editor/core-editor/NanoforgeClient/useGraphics",
- "docs/engine/api/core-editor/core-editor/NanoforgeClient/useInput",
- "docs/engine/api/core-editor/core-editor/NanoforgeClient/useSound",
- "docs/engine/api/core-editor/core-editor/NanoforgeClient",
- "docs/engine/api/core-editor/core-editor/NanoforgeFactory",
- "docs/engine/api/core-editor/core-editor/NanoforgeServer",
- "docs/engine/api/core-editor/core-editor",
- "docs/engine/api/core-editor/index",
- "docs/engine/api/ecs-client/ecs-client/ECSClientLibrary/constructor",
- "docs/engine/api/ecs-client/ecs-client/ECSClientLibrary/__init",
- "docs/engine/api/ecs-client/ecs-client/ECSClientLibrary/__name",
- "docs/engine/api/ecs-client/ecs-client/ECSClientLibrary",
- "docs/engine/api/ecs-client/ecs-client",
- "docs/engine/api/ecs-client/index",
- "docs/engine/api/ecs-lib/ecs-lib/AbstractECSLibrary/constructor",
- "docs/engine/api/ecs-lib/ecs-lib/AbstractECSLibrary/module",
- "docs/engine/api/ecs-lib/ecs-lib/AbstractECSLibrary/__name",
- "docs/engine/api/ecs-lib/ecs-lib/AbstractECSLibrary/path",
- "docs/engine/api/ecs-lib/ecs-lib/AbstractECSLibrary/_registry",
- "docs/engine/api/ecs-lib/ecs-lib/AbstractECSLibrary/registry",
- "docs/engine/api/ecs-lib/ecs-lib/AbstractECSLibrary/__run",
- "docs/engine/api/ecs-lib/ecs-lib/AbstractECSLibrary",
- "docs/engine/api/ecs-lib/ecs-lib/Component",
- "docs/engine/api/ecs-lib/ecs-lib/EditorComponentManifest",
- "docs/engine/api/ecs-lib/ecs-lib/EditorSystemManifest",
- "docs/engine/api/ecs-lib/ecs-lib/Entity/getId",
- "docs/engine/api/ecs-lib/ecs-lib/Entity",
- "docs/engine/api/ecs-lib/ecs-lib/Registry/addComponent",
- "docs/engine/api/ecs-lib/ecs-lib/Registry/addSystem",
- "docs/engine/api/ecs-lib/ecs-lib/Registry/clearEntities",
- "docs/engine/api/ecs-lib/ecs-lib/Registry/clearSystems",
- "docs/engine/api/ecs-lib/ecs-lib/Registry/entityFromIndex",
- "docs/engine/api/ecs-lib/ecs-lib/Registry/getComponentsConst",
- "docs/engine/api/ecs-lib/ecs-lib/Registry/getComponents",
- "docs/engine/api/ecs-lib/ecs-lib/Registry/getEntityComponentConst",
- "docs/engine/api/ecs-lib/ecs-lib/Registry/getEntityComponent",
- "docs/engine/api/ecs-lib/ecs-lib/Registry/getZipper",
- "docs/engine/api/ecs-lib/ecs-lib/Registry/killEntity",
- "docs/engine/api/ecs-lib/ecs-lib/Registry/maxEntities",
- "docs/engine/api/ecs-lib/ecs-lib/Registry/registerComponent",
- "docs/engine/api/ecs-lib/ecs-lib/Registry/removeComponent",
- "docs/engine/api/ecs-lib/ecs-lib/Registry/removeSystem",
- "docs/engine/api/ecs-lib/ecs-lib/Registry/runSystems",
- "docs/engine/api/ecs-lib/ecs-lib/Registry/spawnEntity",
- "docs/engine/api/ecs-lib/ecs-lib/Registry",
- "docs/engine/api/ecs-lib/ecs-lib/SparseArray/clear",
- "docs/engine/api/ecs-lib/ecs-lib/SparseArray/empty",
- "docs/engine/api/ecs-lib/ecs-lib/SparseArray/erase",
- "docs/engine/api/ecs-lib/ecs-lib/SparseArray/getConst",
- "docs/engine/api/ecs-lib/ecs-lib/SparseArray/getIndex",
- "docs/engine/api/ecs-lib/ecs-lib/SparseArray/get",
- "docs/engine/api/ecs-lib/ecs-lib/SparseArray/insertAt_1",
- "docs/engine/api/ecs-lib/ecs-lib/SparseArray/insertAt",
- "docs/engine/api/ecs-lib/ecs-lib/SparseArray/resize",
- "docs/engine/api/ecs-lib/ecs-lib/SparseArray/setByCopy",
- "docs/engine/api/ecs-lib/ecs-lib/SparseArray/setByMove",
- "docs/engine/api/ecs-lib/ecs-lib/SparseArray/set",
- "docs/engine/api/ecs-lib/ecs-lib/SparseArray/size",
- "docs/engine/api/ecs-lib/ecs-lib/SparseArray",
- "docs/engine/api/ecs-lib/ecs-lib/System",
- "docs/engine/api/ecs-lib/ecs-lib",
- "docs/engine/api/ecs-lib/index",
- "docs/engine/api/ecs-server/ecs-server/ECSServerLibrary/constructor",
- "docs/engine/api/ecs-server/ecs-server/ECSServerLibrary/__init",
- "docs/engine/api/ecs-server/ecs-server/ECSServerLibrary/__name",
- "docs/engine/api/ecs-server/ecs-server/ECSServerLibrary",
- "docs/engine/api/ecs-server/ecs-server/Module",
- "docs/engine/api/ecs-server/ecs-server",
- "docs/engine/api/ecs-server/index",
- "docs/engine/api/graphics-2d/graphics-2d/angleDeg",
- "docs/engine/api/graphics-2d/graphics-2d/Animation_2",
- "docs/engine/api/graphics-2d/graphics-2d/ArcConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Arc",
- "docs/engine/api/graphics-2d/graphics-2d/ArrowConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Arrow",
- "docs/engine/api/graphics-2d/graphics-2d/autoDrawEnabled",
- "docs/engine/api/graphics-2d/graphics-2d/Canvas",
- "docs/engine/api/graphics-2d/graphics-2d/capturePointerEventsEnabled",
- "docs/engine/api/graphics-2d/graphics-2d/CircleConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Circle",
- "docs/engine/api/graphics-2d/graphics-2d/ContainerConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Container",
- "docs/engine/api/graphics-2d/graphics-2d/Context",
- "docs/engine/api/graphics-2d/graphics-2d/dblClickWindow",
- "docs/engine/api/graphics-2d/graphics-2d/DD",
- "docs/engine/api/graphics-2d/graphics-2d/document_2",
- "docs/engine/api/graphics-2d/graphics-2d/dragButtons",
- "docs/engine/api/graphics-2d/graphics-2d/dragDistance",
- "docs/engine/api/graphics-2d/graphics-2d/Easings",
- "docs/engine/api/graphics-2d/graphics-2d/EllipseConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Ellipse",
- "docs/engine/api/graphics-2d/graphics-2d/enableTrace",
- "docs/engine/api/graphics-2d/graphics-2d/FastLayer",
- "docs/engine/api/graphics-2d/graphics-2d/Filters",
- "docs/engine/api/graphics-2d/graphics-2d/getAngle",
- "docs/engine/api/graphics-2d/graphics-2d/_global",
- "docs/engine/api/graphics-2d/graphics-2d/Graphics2DLibrary/baseLayer",
- "docs/engine/api/graphics-2d/graphics-2d/Graphics2DLibrary/__init",
- "docs/engine/api/graphics-2d/graphics-2d/Graphics2DLibrary/__name",
- "docs/engine/api/graphics-2d/graphics-2d/Graphics2DLibrary/__run",
- "docs/engine/api/graphics-2d/graphics-2d/Graphics2DLibrary/stage",
- "docs/engine/api/graphics-2d/graphics-2d/Graphics2DLibrary",
- "docs/engine/api/graphics-2d/graphics-2d/GroupConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Group",
- "docs/engine/api/graphics-2d/graphics-2d/hitOnDragEnabled",
- "docs/engine/api/graphics-2d/graphics-2d/Image_2",
- "docs/engine/api/graphics-2d/graphics-2d/ImageConfig",
- "docs/engine/api/graphics-2d/graphics-2d/_injectGlobal",
- "docs/engine/api/graphics-2d/graphics-2d/isBrowser",
- "docs/engine/api/graphics-2d/graphics-2d/isDragging",
- "docs/engine/api/graphics-2d/graphics-2d/isDragReady",
- "docs/engine/api/graphics-2d/graphics-2d/isTransforming",
- "docs/engine/api/graphics-2d/graphics-2d/isUnminified",
- "docs/engine/api/graphics-2d/graphics-2d/KonvaEventListener",
- "docs/engine/api/graphics-2d/graphics-2d/KonvaEventObject",
- "docs/engine/api/graphics-2d/graphics-2d/KonvaPointerEvent",
- "docs/engine/api/graphics-2d/graphics-2d/LabelConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Label",
- "docs/engine/api/graphics-2d/graphics-2d/LayerConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Layer",
- "docs/engine/api/graphics-2d/graphics-2d/legacyTextRendering",
- "docs/engine/api/graphics-2d/graphics-2d/LineConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Line",
- "docs/engine/api/graphics-2d/graphics-2d/_mouseDblClickPointerId",
- "docs/engine/api/graphics-2d/graphics-2d/_mouseInDblClickWindow",
- "docs/engine/api/graphics-2d/graphics-2d/_mouseListenClick",
- "docs/engine/api/graphics-2d/graphics-2d/Node_2",
- "docs/engine/api/graphics-2d/graphics-2d/NodeConfig",
- "docs/engine/api/graphics-2d/graphics-2d/PathConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Path",
- "docs/engine/api/graphics-2d/graphics-2d/pixelRatio",
- "docs/engine/api/graphics-2d/graphics-2d/_pointerDblClickPointerId",
- "docs/engine/api/graphics-2d/graphics-2d/pointerEventsEnabled",
- "docs/engine/api/graphics-2d/graphics-2d/_pointerInDblClickWindow",
- "docs/engine/api/graphics-2d/graphics-2d/_pointerListenClick",
- "docs/engine/api/graphics-2d/graphics-2d/RectConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Rect",
- "docs/engine/api/graphics-2d/graphics-2d/RegularPolygonConfig",
- "docs/engine/api/graphics-2d/graphics-2d/RegularPolygon",
- "docs/engine/api/graphics-2d/graphics-2d/releaseCanvasOnDestroy",
- "docs/engine/api/graphics-2d/graphics-2d/_renderBackend",
- "docs/engine/api/graphics-2d/graphics-2d/RingConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Ring",
- "docs/engine/api/graphics-2d/graphics-2d/ShapeConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Shape",
- "docs/engine/api/graphics-2d/graphics-2d/shapes",
- "docs/engine/api/graphics-2d/graphics-2d/showWarnings",
- "docs/engine/api/graphics-2d/graphics-2d/SpriteConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Sprite",
- "docs/engine/api/graphics-2d/graphics-2d/StageConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Stage",
- "docs/engine/api/graphics-2d/graphics-2d/stages",
- "docs/engine/api/graphics-2d/graphics-2d/StarConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Star",
- "docs/engine/api/graphics-2d/graphics-2d/TagConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Tag",
- "docs/engine/api/graphics-2d/graphics-2d/Text_2",
- "docs/engine/api/graphics-2d/graphics-2d/TextConfig",
- "docs/engine/api/graphics-2d/graphics-2d/TextPathConfig",
- "docs/engine/api/graphics-2d/graphics-2d/TextPath",
- "docs/engine/api/graphics-2d/graphics-2d/_touchDblClickPointerId",
- "docs/engine/api/graphics-2d/graphics-2d/_touchInDblClickWindow",
- "docs/engine/api/graphics-2d/graphics-2d/_touchListenClick",
- "docs/engine/api/graphics-2d/graphics-2d/Transformer_2",
- "docs/engine/api/graphics-2d/graphics-2d/TransformerConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Transform",
- "docs/engine/api/graphics-2d/graphics-2d/TweenConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Tween",
- "docs/engine/api/graphics-2d/graphics-2d/Util",
- "docs/engine/api/graphics-2d/graphics-2d/Vector2d",
- "docs/engine/api/graphics-2d/graphics-2d/version",
- "docs/engine/api/graphics-2d/graphics-2d/WedgeConfig",
- "docs/engine/api/graphics-2d/graphics-2d/Wedge",
- "docs/engine/api/graphics-2d/graphics-2d",
- "docs/engine/api/graphics-2d/index",
- "docs/engine/api/input/index",
- "docs/engine/api/input/input/InputEnum",
- "docs/engine/api/input/input/InputLibrary/constructor",
- "docs/engine/api/input/input/InputLibrary/getDragState",
- "docs/engine/api/input/input/InputLibrary/getMousePosition",
- "docs/engine/api/input/input/InputLibrary/getMouseState",
- "docs/engine/api/input/input/InputLibrary/getPressedKeys",
- "docs/engine/api/input/input/InputLibrary/getWheelState",
- "docs/engine/api/input/input/InputLibrary/__init",
- "docs/engine/api/input/input/InputLibrary/isDragging",
- "docs/engine/api/input/input/InputLibrary/isKeyPressed",
- "docs/engine/api/input/input/InputLibrary/__name",
- "docs/engine/api/input/input/InputLibrary/__run",
- "docs/engine/api/input/input/InputLibrary",
- "docs/engine/api/input/input",
- "docs/engine/api/music/index",
- "docs/engine/api/music/music/MusicLibrary/__init",
- "docs/engine/api/music/music/MusicLibrary/load",
- "docs/engine/api/music/music/MusicLibrary/mute",
- "docs/engine/api/music/music/MusicLibrary/__name",
- "docs/engine/api/music/music/MusicLibrary/play",
- "docs/engine/api/music/music/MusicLibrary",
- "docs/engine/api/music/music",
- "docs/engine/api/network-client/index",
- "docs/engine/api/network-client/network-client/NetworkClientLibrary/__init",
- "docs/engine/api/network-client/network-client/NetworkClientLibrary/__name",
- "docs/engine/api/network-client/network-client/NetworkClientLibrary/tcp",
- "docs/engine/api/network-client/network-client/NetworkClientLibrary/udp",
- "docs/engine/api/network-client/network-client/NetworkClientLibrary",
- "docs/engine/api/network-client/network-client/TCPClient/connect",
- "docs/engine/api/network-client/network-client/TCPClient/constructor",
- "docs/engine/api/network-client/network-client/TCPClient/getReceivedPackets",
- "docs/engine/api/network-client/network-client/TCPClient/isConnected",
- "docs/engine/api/network-client/network-client/TCPClient/sendData",
- "docs/engine/api/network-client/network-client/TCPClient",
- "docs/engine/api/network-client/network-client/UDPClient/connect",
- "docs/engine/api/network-client/network-client/UDPClient/constructor",
- "docs/engine/api/network-client/network-client/UDPClient/getReceivedPackets",
- "docs/engine/api/network-client/network-client/UDPClient/isConnected",
- "docs/engine/api/network-client/network-client/UDPClient/sendData",
- "docs/engine/api/network-client/network-client/UDPClient",
- "docs/engine/api/network-client/network-client",
- "docs/engine/api/network-server/index",
- "docs/engine/api/network-server/network-server/NetworkServerLibrary/__init",
- "docs/engine/api/network-server/network-server/NetworkServerLibrary/__name",
- "docs/engine/api/network-server/network-server/NetworkServerLibrary/tcp",
- "docs/engine/api/network-server/network-server/NetworkServerLibrary/udp",
- "docs/engine/api/network-server/network-server/NetworkServerLibrary",
- "docs/engine/api/network-server/network-server/TCPServer/constructor",
- "docs/engine/api/network-server/network-server/TCPServer/getConnectedClients",
- "docs/engine/api/network-server/network-server/TCPServer/getReceivedPackets",
- "docs/engine/api/network-server/network-server/TCPServer/listen",
- "docs/engine/api/network-server/network-server/TCPServer/sendToClient",
- "docs/engine/api/network-server/network-server/TCPServer/sendToEverybody",
- "docs/engine/api/network-server/network-server/TCPServer",
- "docs/engine/api/network-server/network-server/UDPServer/constructor",
- "docs/engine/api/network-server/network-server/UDPServer/getConnectedClients",
- "docs/engine/api/network-server/network-server/UDPServer/getReceivedPackets",
- "docs/engine/api/network-server/network-server/UDPServer/listen",
- "docs/engine/api/network-server/network-server/UDPServer/sendToClient",
- "docs/engine/api/network-server/network-server/UDPServer/sendToEverybody",
- "docs/engine/api/network-server/network-server/UDPServer",
- "docs/engine/api/network-server/network-server",
- "docs/engine/api/sound/index",
- "docs/engine/api/sound/sound/SoundLibrary/__init",
- "docs/engine/api/sound/sound/SoundLibrary/load",
- "docs/engine/api/sound/sound/SoundLibrary/mute",
- "docs/engine/api/sound/sound/SoundLibrary/__name",
- "docs/engine/api/sound/sound/SoundLibrary/play",
- "docs/engine/api/sound/sound/SoundLibrary",
- "docs/engine/api/sound/sound",
- "docs/engine/documentation",
- "docs/engine/how_to_use",
- "docs/engine/index",
- "docs/engine/network/index",
- "docs/engine/network/network-client-api",
- "docs/engine/network/network-client",
- "docs/engine/network/network-server-api",
- "docs/engine/network/network-server",
- "docs/engine/network/packet-framing",
- "docs/engine/registry/index",
- "docs/engine/registry/writing_web_assembly"
- ]
- }
-}
diff --git a/docs/templates/class.liquid b/docs/templates/class.liquid
new file mode 100644
index 00000000..6dae92ac
--- /dev/null
+++ b/docs/templates/class.liquid
@@ -0,0 +1,109 @@
+{%- layout "layout" %}
+
+{%- block content %}
+
+{%- if apiItem.signature %}
+## Signature
+
+```typescript
+{{ apiItem.signature }}
+```
+{%- endif %}
+
+{%- if constructors and constructors.size > 0 %}
+
+## Constructors
+
+{%- for constructor in constructors %}
+
+### {{ constructor.title }}
+
+{%- if constructor.modifiers and constructor.modifiers.size > 0 %}
+**Modifiers**: {{ constructor.modifiers | join: ', ' }}
+{%- endif %}
+{%- if constructor.description %}
+
+{{ constructor.description }}
+{%- endif %}
+{%- endfor %}
+{%- endif %}
+
+{%- if properties and properties.size > 0 %}
+
+## Properties
+
+{%- for property in properties %}
+
+### {{ property.title }}
+
+{%- if property.modifiers and property.modifiers.size > 0 %}
+**Modifiers**: {{ property.modifiers | join: ', ' }}
+{%- endif %}
+{%- if property.type %}
+{%- assign formatted_prop_type = property.type | format_type %}
+{%- if formatted_prop_type contains "```" %}
+**Type**:{{ formatted_prop_type }}
+{%- else %}
+**Type**: {%- if property.typeRef and autolink != false %}`{{ formatted_prop_type }}`{%- elsif property.typePath %}[`{{ formatted_prop_type }}`]({{ property.typePath }}){%- else %}`{{ formatted_prop_type }}`{%- endif %}
+{%- endif %}
+{%- endif %}
+{%- if property.isOptional %}
+**Optional**: Yes
+{%- endif %}
+{%- if property.isInherited %}
+**Inherited**: Yes
+{%- endif %}
+{%- if property.defaultValue and property.defaultValue.size > 0 %}
+**Default**: `{{ property.defaultValue }}`
+{%- endif %}
+{%- if property.description %}
+
+{{ property.description }}
+{%- endif %}
+{%- endfor %}
+{%- endif %}
+
+{%- if methods and methods.size > 0 %}
+
+## Methods
+
+{%- for method in methods %}
+
+### {{ method.title }}
+
+{%- if method.modifiers and method.modifiers.size > 0 %}
+**Modifiers**: {{ method.modifiers | join: ', ' }}
+{%- endif %}
+{%- if method.isInherited %}
+**Inherited**: Yes
+{%- endif %}
+{%- if method.description %}
+
+{{ method.description }}
+{%- endif %}
+{%- endfor %}
+{%- endif %}
+
+{%- if events and events.size > 0 %}
+
+## Events
+
+{%- for event in events %}
+
+### {{ event.title }}
+
+{%- if event.type %}
+{%- assign formatted_event_type = event.type | format_type %}
+{%- if formatted_event_type contains "```" %}
+**Type**:{{ formatted_event_type }}
+{%- else %}
+**Type**: {%- if event.typeRef and autolink != false %}`{{ formatted_event_type }}`{%- elsif event.typePath %}[`{{ formatted_event_type }}`]({{ event.typePath }}){%- else %}`{{ formatted_event_type }}`{%- endif %}
+{%- endif %}
+{%- endif %}
+{%- if event.description %}
+
+{{ event.description }}
+{%- endif %}
+{%- endfor %}
+{%- endif %}
+{%- endblock %}
diff --git a/docs/templates/constructor.liquid b/docs/templates/constructor.liquid
new file mode 100644
index 00000000..5ef2b43a
--- /dev/null
+++ b/docs/templates/constructor.liquid
@@ -0,0 +1,41 @@
+{%- layout "layout" %}
+
+{%- block content %}
+
+{%- if apiItem.signature %}
+## Signature
+
+```typescript
+{{ apiItem.signature }}
+```
+{%- endif %}
+
+{%- if parameters and parameters.size > 0 %}
+
+## Parameters
+
+{%- for parameter in parameters %}
+
+### {{ parameter.title }}
+
+{%- if parameter.type %}
+{%- assign formatted_param_type = parameter.type | format_type %}
+{%- if formatted_param_type contains "```" %}
+- **Type**:{{ formatted_param_type }}
+{%- else %}
+- **Type**: {%- if parameter.typeRef and autolink != false %}`{{ formatted_param_type }}`{%- elsif parameter.typePath -%}[`{{ formatted_param_type }}`]({{ parameter.typePath }}){%- else -%}`{{ formatted_param_type }}`{%- endif %}
+{%- endif %}
+{%- endif %}
+{%- if parameter.isOptional %}
+- **Optional**: Yes
+{%- endif %}
+{%- if parameter.defaultValue %}
+- **Default**: `{{ parameter.defaultValue }}`
+{%- endif %}
+{%- if parameter.description %}
+
+{{ parameter.description }}
+{%- endif %}
+{%- endfor %}
+{%- endif %}
+{%- endblock %}
diff --git a/docs/templates/entry-point.liquid b/docs/templates/entry-point.liquid
new file mode 100644
index 00000000..7a46890e
--- /dev/null
+++ b/docs/templates/entry-point.liquid
@@ -0,0 +1,108 @@
+{%- layout "layout" %}
+
+{%- block content %}
+
+{%- if abstractClasses and abstractClasses.size > 0 %}
+## Abstract Classes
+
+{%- for item in abstractClasses %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if classes and classes.size > 0 %}
+## Classes
+
+{%- for item in classes %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if enumerations and enumerations.size > 0 %}
+## Enumerations
+
+{%- for item in enumerations %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if functions and functions.size > 0 %}
+## Functions
+
+{%- for item in functions %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if interfaces and interfaces.size > 0 %}
+## Interfaces
+
+{%- for item in interfaces %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if namespaces and namespaces.size > 0 %}
+## Namespaces
+
+{%- for item in namespaces %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if typeAliases and typeAliases.size > 0 %}
+## Type Aliases
+
+{%- for item in typeAliases %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if variables and variables.size > 0 %}
+## Variables
+
+{%- for item in variables %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+{%- endblock %}
diff --git a/docs/templates/enum-member.liquid b/docs/templates/enum-member.liquid
new file mode 100644
index 00000000..21947c4e
--- /dev/null
+++ b/docs/templates/enum-member.liquid
@@ -0,0 +1,10 @@
+{%- layout "layout" %}
+
+{%- block content %}
+{%- if apiItem.defaultValue %}
+
+## Value
+
+`{{ apiItem.defaultValue }}`
+{%- endif %}
+{%- endblock %}
diff --git a/docs/templates/enum.liquid b/docs/templates/enum.liquid
new file mode 100644
index 00000000..9a6e157d
--- /dev/null
+++ b/docs/templates/enum.liquid
@@ -0,0 +1,27 @@
+{%- layout "layout" %}
+
+{%- block content %}
+
+{%- if members and members.size > 0 %}
+{%- assign showValues = true %}
+{%- if rendering and rendering.hideStringEnumValues == true %}
+{%- assign showValues = false %}
+{%- endif %}
+
+## Members
+
+{%- if showValues %}
+| Member | Value | Description |
+| ------ | ----- | ----------- |
+{%- for member in members %}
+| `{{ member.title }}` | `{{ member.defaultValue }}` | {{ member.description | default: "" }} |
+{%- endfor %}
+{%- else %}
+| Member | Description |
+| ------ | ----------- |
+{%- for member in members %}
+| `{{ member.title }}` | {{ member.description | default: "" }} |
+{%- endfor %}
+{%- endif %}
+{%- endif %}
+{%- endblock %}
diff --git a/docs/templates/function.liquid b/docs/templates/function.liquid
new file mode 100644
index 00000000..abdea231
--- /dev/null
+++ b/docs/templates/function.liquid
@@ -0,0 +1,67 @@
+{%- layout "layout" %}
+
+{%- block content %}
+
+{%- if apiItem.signature %}
+## Signature
+
+```typescript
+{{ apiItem.signature }}
+```
+{%- endif %}
+
+{%- if parameters and parameters.size > 0 or returnType %}
+
+## Parameters
+
+{%- if parameters and parameters.size > 0 %}
+{%- for parameter in parameters %}
+
+### {{ parameter.title }}
+
+{%- if parameter.type %}
+{%- assign formatted_param_type = parameter.type | format_type %}
+{%- if formatted_param_type contains "```" %}
+**Type**:{{ formatted_param_type }}
+{%- else %}
+**Type**: {%- if parameter.typeRef and autolink != false %}`{{ formatted_param_type }}`{%- elsif parameter.typePath -%}[`{{ formatted_param_type }}`]({{ parameter.typePath }}){%- else -%}`{{ formatted_param_type }}`{%- endif %}
+{%- endif %}
+{%- endif %}
+{%- if parameter.isOptional %}
+**Optional**: Yes
+{%- endif %}
+{%- if parameter.defaultValue %}
+**Default**: `{{ parameter.defaultValue }}`
+{%- endif %}
+{%- if parameter.description %}
+
+{{ parameter.description }}
+{%- endif %}
+{%- endfor %}
+{%- else %}
+
+*No parameters.*
+{%- endif %}
+
+## Returns
+
+{%- if returnType and returnType.type %}
+{%- assign formatted_return_type = returnType.type | format_type %}
+{%- if formatted_return_type contains "```" %}
+
+**Type**:{{ formatted_return_type }}
+{%- else %}
+
+**Type**: {%- if returnType.typeRef and autolink != false %}`{{ formatted_return_type }}`{%- elsif returnType.typePath -%}[`{{ formatted_return_type }}`]({{ returnType.typePath }}){%- else -%}`{{ formatted_return_type }}`{%- endif %}
+{%- endif %}
+{%- endif %}
+{%- if returnType and returnType.description %}
+
+{{ returnType.description }}
+{%- endif %}
+{%- if not returnType or not returnType.type %}
+
+`void`
+{%- endif %}
+{%- endif %}
+{%- endblock %}
diff --git a/docs/templates/generic.liquid b/docs/templates/generic.liquid
new file mode 100644
index 00000000..dacb8c60
--- /dev/null
+++ b/docs/templates/generic.liquid
@@ -0,0 +1,10 @@
+{%- layout "layout" %}
+
+{%- block content %}
+{%- if apiItem.description %}
+
+## Description
+
+{{ apiItem.description }}
+{%- endif %}
+{%- endblock %}
diff --git a/docs/templates/interface.liquid b/docs/templates/interface.liquid
new file mode 100644
index 00000000..0fd244a0
--- /dev/null
+++ b/docs/templates/interface.liquid
@@ -0,0 +1,88 @@
+{%- layout "layout" %}
+
+{%- block content %}
+
+{%- if apiItem.signature %}
+## Signature
+
+```typescript
+{{ apiItem.signature }}
+```
+{%- endif %}
+
+{%- if properties and properties.size > 0 %}
+
+## Properties
+
+{%- for property in properties %}
+
+### {{ property.title }}
+
+{%- if property.modifiers and property.modifiers.size > 0 %}
+**Modifiers**: {{ property.modifiers | join: ', ' }}
+{%- endif %}
+{%- if property.type %}
+{%- assign formatted_prop_type = property.type | format_type %}
+{%- if formatted_prop_type contains "```" %}
+**Type**:{{ formatted_prop_type }}
+{%- else %}
+**Type**: {%- if property.typeRef and autolink != false %}`{{ formatted_prop_type }}`{%- elsif property.typePath %}[`{{ formatted_prop_type }}`]({{ property.typePath }}){%- else %}`{{ formatted_prop_type }}`{%- endif %}
+{%- endif %}
+{%- endif %}
+{%- if property.isOptional %}
+**Optional**: Yes
+{%- endif %}
+{%- if property.isInherited %}
+**Inherited**: Yes
+{%- endif %}
+{%- if property.description %}
+
+{{ property.description }}
+{%- endif %}
+{%- endfor %}
+{%- endif %}
+
+{%- if methods and methods.size > 0 %}
+
+## Methods
+
+{%- for method in methods %}
+
+### {{ method.title }}
+
+{%- if method.modifiers and method.modifiers.size > 0 %}
+**Modifiers**: {{ method.modifiers | join: ', ' }}
+{%- endif %}
+{%- if method.isInherited %}
+**Inherited**: Yes
+{%- endif %}
+{%- if method.description %}
+
+{{ method.description }}
+{%- endif %}
+{%- endfor %}
+{%- endif %}
+
+{%- if events and events.size > 0 %}
+
+## Events
+
+{%- for event in events %}
+
+### {{ event.title }}
+
+{%- if event.type %}
+{%- assign formatted_event_type = event.type | format_type %}
+{%- if formatted_event_type contains "```" %}
+**Type**:{{ formatted_event_type }}
+{%- else %}
+**Type**: {%- if event.typeRef and autolink != false %}`{{ formatted_event_type }}`{%- elsif event.typePath %}[`{{ formatted_event_type }}`]({{ event.typePath }}){%- else %}`{{ formatted_event_type }}`{%- endif %}
+{%- endif %}
+{%- endif %}
+{%- if event.description %}
+
+{{ event.description }}
+{%- endif %}
+{%- endfor %}
+{%- endif %}
+{%- endblock %}
diff --git a/docs/templates/layout.liquid b/docs/templates/layout.liquid
new file mode 100644
index 00000000..5db2f048
--- /dev/null
+++ b/docs/templates/layout.liquid
@@ -0,0 +1,95 @@
+---
+title: "{{ page.title }}"
+{%- if page.icon %}
+icon: "{{ page.icon }}"
+{%- endif %}
+description: "{{ page.description }}"
+---
+
+import { PageLink } from '/snippets/tsdocs/PageLink.jsx';
+import { RefLink } from '/snippets/tsdocs/RefLink.jsx';
+
+# {{ apiItem.displayName }}
+
+{%- block warnings %}
+{%- if apiItem.isDeprecated %}
+
+
+ **Deprecated**: This {{ apiItem.kind | downcase }} is deprecated and may be removed in a future version.
+
+{%- endif %}
+{%- if apiItem.isAlpha %}
+
+
+ **Alpha**: This {{ apiItem.kind | downcase }} is in alpha and may change without notice.
+
+{%- endif %}
+{%- if apiItem.isBeta %}
+
+
+ **Beta**: This {{ apiItem.kind | downcase }} is in beta and may change without notice.
+
+{%- endif %}
+{%- endblock %}
+
+{%- block summary %}
+{%- if apiItem.summary and apiItem.summary.size > 0 %}
+
+## Summary
+
+{{ apiItem.summary | render_segments }}
+{%- endif %}
+{%- endblock %}
+
+{%- block heritage %}
+{%- if heritageTypes and heritageTypes.size > 0 %}
+
+## Heritage
+
+{%- for type in heritageTypes %}
+{%- if type.path %}
+* [{{ type.name }}]({{ type.path }})
+{%- else %}
+* {{ type.name }}
+{%- endif %}
+{%- endfor %}
+{%- endif %}
+{%- endblock %}
+
+{%- block content %}{% endblock %}
+
+{%- block remarks %}
+{%- if apiItem.remarks and apiItem.remarks.size > 0 %}
+
+## Remarks
+
+{{ apiItem.remarks | render_segments }}
+{%- endif %}
+{%- endblock %}
+
+{%- block examples %}
+{%- if examples and examples.size > 0 %}
+
+## Examples
+
+{%- for example in examples %}
+
+### Example {{ forloop.index }}
+
+```typescript
+{{ example }}
+```
+{%- endfor %}
+{%- endif %}
+{%- endblock %}
+
+{%- block guides %}
+{%- if guides and guides.size > 0 %}
+
+## Related Documentation
+
+{%- for guide in guides %}
+- {{ guide.description }}
+{%- endfor %}
+{%- endif %}
+{%- endblock %}
\ No newline at end of file
diff --git a/docs/templates/method.liquid b/docs/templates/method.liquid
new file mode 100644
index 00000000..abdea231
--- /dev/null
+++ b/docs/templates/method.liquid
@@ -0,0 +1,67 @@
+{%- layout "layout" %}
+
+{%- block content %}
+
+{%- if apiItem.signature %}
+## Signature
+
+```typescript
+{{ apiItem.signature }}
+```
+{%- endif %}
+
+{%- if parameters and parameters.size > 0 or returnType %}
+
+## Parameters
+
+{%- if parameters and parameters.size > 0 %}
+{%- for parameter in parameters %}
+
+### {{ parameter.title }}
+
+{%- if parameter.type %}
+{%- assign formatted_param_type = parameter.type | format_type %}
+{%- if formatted_param_type contains "```" %}
+**Type**:{{ formatted_param_type }}
+{%- else %}
+**Type**: {%- if parameter.typeRef and autolink != false %}`{{ formatted_param_type }}`{%- elsif parameter.typePath -%}[`{{ formatted_param_type }}`]({{ parameter.typePath }}){%- else -%}`{{ formatted_param_type }}`{%- endif %}
+{%- endif %}
+{%- endif %}
+{%- if parameter.isOptional %}
+**Optional**: Yes
+{%- endif %}
+{%- if parameter.defaultValue %}
+**Default**: `{{ parameter.defaultValue }}`
+{%- endif %}
+{%- if parameter.description %}
+
+{{ parameter.description }}
+{%- endif %}
+{%- endfor %}
+{%- else %}
+
+*No parameters.*
+{%- endif %}
+
+## Returns
+
+{%- if returnType and returnType.type %}
+{%- assign formatted_return_type = returnType.type | format_type %}
+{%- if formatted_return_type contains "```" %}
+
+**Type**:{{ formatted_return_type }}
+{%- else %}
+
+**Type**: {%- if returnType.typeRef and autolink != false %}`{{ formatted_return_type }}`{%- elsif returnType.typePath -%}[`{{ formatted_return_type }}`]({{ returnType.typePath }}){%- else -%}`{{ formatted_return_type }}`{%- endif %}
+{%- endif %}
+{%- endif %}
+{%- if returnType and returnType.description %}
+
+{{ returnType.description }}
+{%- endif %}
+{%- if not returnType or not returnType.type %}
+
+`void`
+{%- endif %}
+{%- endif %}
+{%- endblock %}
diff --git a/docs/templates/model.liquid b/docs/templates/model.liquid
new file mode 100644
index 00000000..230abdb5
--- /dev/null
+++ b/docs/templates/model.liquid
@@ -0,0 +1,8 @@
+{%- layout "layout" %}
+
+{%- block content %}
+{%- if apiItem.description %}
+
+{{ apiItem.description }}
+{%- endif %}
+{%- endblock %}
diff --git a/docs/templates/namespace.liquid b/docs/templates/namespace.liquid
new file mode 100644
index 00000000..c8ab5888
--- /dev/null
+++ b/docs/templates/namespace.liquid
@@ -0,0 +1,116 @@
+{%- layout "layout" %}
+
+{%- block content %}
+
+{%- if apiItem.signature %}
+## Signature
+
+```typescript
+{{ apiItem.signature }}
+```
+{%- endif %}
+
+{%- if abstractClasses and abstractClasses.size > 0 %}
+## Abstract Classes
+
+{%- for item in abstractClasses %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if classes and classes.size > 0 %}
+## Classes
+
+{%- for item in classes %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if enumerations and enumerations.size > 0 %}
+## Enumerations
+
+{%- for item in enumerations %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if functions and functions.size > 0 %}
+## Functions
+
+{%- for item in functions %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if interfaces and interfaces.size > 0 %}
+## Interfaces
+
+{%- for item in interfaces %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if namespaces and namespaces.size > 0 %}
+## Namespaces
+
+{%- for item in namespaces %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if typeAliases and typeAliases.size > 0 %}
+## Type Aliases
+
+{%- for item in typeAliases %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if variables and variables.size > 0 %}
+## Variables
+
+{%- for item in variables %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+{%- endblock %}
diff --git a/docs/templates/package.liquid b/docs/templates/package.liquid
new file mode 100644
index 00000000..7a46890e
--- /dev/null
+++ b/docs/templates/package.liquid
@@ -0,0 +1,108 @@
+{%- layout "layout" %}
+
+{%- block content %}
+
+{%- if abstractClasses and abstractClasses.size > 0 %}
+## Abstract Classes
+
+{%- for item in abstractClasses %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if classes and classes.size > 0 %}
+## Classes
+
+{%- for item in classes %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if enumerations and enumerations.size > 0 %}
+## Enumerations
+
+{%- for item in enumerations %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if functions and functions.size > 0 %}
+## Functions
+
+{%- for item in functions %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if interfaces and interfaces.size > 0 %}
+## Interfaces
+
+{%- for item in interfaces %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if namespaces and namespaces.size > 0 %}
+## Namespaces
+
+{%- for item in namespaces %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if typeAliases and typeAliases.size > 0 %}
+## Type Aliases
+
+{%- for item in typeAliases %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+
+{%- if variables and variables.size > 0 %}
+## Variables
+
+{%- for item in variables %}
+### [{{ item.title }}]({{ item.titlePath }})
+
+{%- if item.description %}
+{{ item.description }}
+{%- endif %}
+
+{%- endfor %}
+{%- endif %}
+{%- endblock %}
diff --git a/docs/templates/property.liquid b/docs/templates/property.liquid
new file mode 100644
index 00000000..740bde27
--- /dev/null
+++ b/docs/templates/property.liquid
@@ -0,0 +1,23 @@
+{%- layout "layout" %}
+
+{%- block content %}
+{%- if returnType %}
+
+## Type
+
+{%- if returnType.type %}
+{%- assign formatted_type = returnType.type | format_type %}
+{%- if formatted_type contains "```" %}
+
+**Type**:{{ formatted_type }}
+{%- else %}
+
+**Type**: {%- if returnType.typePath -%}[`{{ formatted_type }}`]({{ returnType.typePath }}){%- else -%}`{{ formatted_type }}`{%- endif %}
+{%- endif %}
+{%- endif %}
+{%- if returnType.description %}
+
+{{ returnType.description }}
+{%- endif %}
+{%- endif %}
+{%- endblock %}
diff --git a/docs/templates/type-alias.liquid b/docs/templates/type-alias.liquid
new file mode 100644
index 00000000..1f1ed547
--- /dev/null
+++ b/docs/templates/type-alias.liquid
@@ -0,0 +1,41 @@
+{%- layout "layout" %}
+
+{%- block content %}
+
+{%- if apiItem.signature %}
+## Signature
+
+```typescript
+{{ apiItem.signature }}
+```
+{%- endif %}
+
+{%- if parameters and parameters.size > 0 %}
+
+## Type Parameters
+
+{%- for parameter in parameters %}
+
+### {{ parameter.title }}
+
+{%- if parameter.type %}
+{%- assign formatted_param_type = parameter.type | format_type %}
+{%- if formatted_param_type contains "```" %}
+**Type**:{{ formatted_param_type }}
+{%- else %}
+**Type**: {%- if parameter.typePath -%}[`{{ formatted_param_type }}`]({{ parameter.typePath }}){%- else -%}`{{ formatted_param_type }}`{%- endif %}
+{%- endif %}
+{%- endif %}
+{%- if parameter.isOptional %}
+**Optional**: Yes
+{%- endif %}
+{%- if parameter.defaultValue %}
+**Default**: `{{ parameter.defaultValue }}`
+{%- endif %}
+{%- if parameter.description %}
+
+{{ parameter.description }}
+{%- endif %}
+{%- endfor %}
+{%- endif %}
+{%- endblock %}
diff --git a/docs/templates/variable.liquid b/docs/templates/variable.liquid
new file mode 100644
index 00000000..a1db6b11
--- /dev/null
+++ b/docs/templates/variable.liquid
@@ -0,0 +1,32 @@
+{%- layout "layout" %}
+
+{%- block content %}
+
+{%- if apiItem.signature %}
+## Signature
+
+```typescript
+{{ apiItem.signature }}
+```
+{%- endif %}
+
+{%- if returnType %}
+
+## Type
+
+{%- if returnType.type %}
+{%- assign formatted_type = returnType.type | format_type %}
+{%- if formatted_type contains "```" %}
+
+**Type**:{{ formatted_type }}
+{%- else %}
+
+**Type**: {%- if returnType.typeRef and autolink != false %}`{{ formatted_type }}`{%- elsif returnType.typePath -%}[`{{ formatted_type }}`]({{ returnType.typePath }}){%- else -%}`{{ formatted_type }}`{%- endif %}
+{%- endif %}
+{%- endif %}
+{%- if returnType.description %}
+
+{{ returnType.description }}
+{%- endif %}
+{%- endif %}
+{%- endblock %}
diff --git a/package.json b/package.json
index e54367c9..19019905 100644
--- a/package.json
+++ b/package.json
@@ -26,7 +26,7 @@
"test:unit": "turbo run test:unit --concurrency=5",
"test:e2e": "vitest run --config vitest.config.e2e.ts",
"prepare": "husky",
- "docs": "turbo run mint-tsdocs --concurrency=5"
+ "docs": "turbo run docs --concurrency=5 && ./scripts/sync-docs-references.sh"
},
"devDependencies": {
"@commitlint/cli": "catalog:ci",
@@ -48,7 +48,7 @@
"typescript": "catalog:core",
"vitest": "catalog:test"
},
- "packageManager": "pnpm@11.3.0",
+ "packageManager": "pnpm@11.5.2",
"engines": {
"node": "25"
},
diff --git a/packages/asset-manager/README.md b/packages/asset-manager/README.md
index 7000a76c..ec968ef6 100644
--- a/packages/asset-manager/README.md
+++ b/packages/asset-manager/README.md
@@ -7,10 +7,9 @@
-
-
+
-
+
diff --git a/packages/asset-manager/mint-tsdocs.config.json b/packages/asset-manager/mint-tsdocs.config.json
index 1d45efe5..56abf931 100644
--- a/packages/asset-manager/mint-tsdocs.config.json
+++ b/packages/asset-manager/mint-tsdocs.config.json
@@ -1,10 +1,13 @@
{
"$schema": "./node_modules/mint-tsdocs/lib/schemas/config.schema.json",
- "entryPoint": "dist/index.d.cts",
- "outputFolder": "../../references/asset-manager",
+ "entryPoint": "dist/index.d.ts",
+ "outputFolder": "../../docs/references/asset-manager",
"lint": {
"eslint": {
"enabled": true
}
+ },
+ "templates": {
+ "userTemplateDir": "../../docs/templates"
}
}
diff --git a/packages/asset-manager/package.json b/packages/asset-manager/package.json
index e4f45f39..b2aaa2c0 100644
--- a/packages/asset-manager/package.json
+++ b/packages/asset-manager/package.json
@@ -54,7 +54,7 @@
"prepack": "pnpm run build && pnpm run lint",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/asset-manager/*'",
"release": "cliff-jumper",
- "mint-tsdocs": "mint-tsdocs generate"
+ "docs": "mint-tsdocs generate"
},
"dependencies": {
"@nanoforge-dev/common": "workspace:*"
@@ -71,7 +71,7 @@
"unrun": "catalog:build",
"vitest": "catalog:test"
},
- "packageManager": "pnpm@10.33.0",
+ "packageManager": "pnpm@11.5.2",
"engines": {
"node": "25"
},
diff --git a/packages/asset-manager/src/asset-manager.library.ts b/packages/asset-manager/src/asset-manager.library.ts
index 67b28abd..df0a5e6b 100644
--- a/packages/asset-manager/src/asset-manager.library.ts
+++ b/packages/asset-manager/src/asset-manager.library.ts
@@ -5,17 +5,48 @@ import {
NfNotFound,
} from "@nanoforge-dev/common";
+/**
+ * Built-in asset-manager library.
+ *
+ * @remarks
+ * Stores the file map injected by the NanoForge loader (`nf start`) and
+ * exposes assets via `getAsset`. Register it with the application before
+ * calling `init`:
+ *
+ * ```ts
+ * const client = NanoforgeFactory.createClient();
+ * client.useAssetManager(new AssetManagerLibrary());
+ * await client.init(`container, files, env `);
+ * ```
+ *
+ * File paths are normalised on lookup: leading slashes are collapsed to a
+ * single `/`, duplicate slashes are removed, and trailing slashes are stripped.
+ */
export class AssetManagerLibrary extends BaseAssetManagerLibrary {
private _assets?: Map;
+ /** @internal */
get __name(): string {
return "AssetManagerLibrary";
}
+ /** @internal */
public async __init(context: InitContext): Promise {
this._assets = context.files;
}
+ /**
+ * Retrieve a registered file asset by its virtual path.
+ *
+ * @remarks
+ * The path is normalised before lookup: leading and duplicate slashes are
+ * collapsed and trailing slashes are removed.
+ *
+ * @param path - Virtual path of the asset (e.g. "/textures/hero.png").
+ * @returns An `NfFile` handle for the requested asset.
+ * @throws `NfNotFound` When no asset is registered at the given path.
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
+ */
public getAsset(path: string): NfFile {
if (!this._assets) this.throwNotInitializedError();
const res = this._assets.get(this._parsePath(path));
diff --git a/packages/common/README.md b/packages/common/README.md
index b64cf8ee..a874391b 100644
--- a/packages/common/README.md
+++ b/packages/common/README.md
@@ -7,10 +7,9 @@
-
-
+
-
+
diff --git a/packages/common/mint-tsdocs.config.json b/packages/common/mint-tsdocs.config.json
index 90664b43..86e8e19a 100644
--- a/packages/common/mint-tsdocs.config.json
+++ b/packages/common/mint-tsdocs.config.json
@@ -1,10 +1,13 @@
{
"$schema": "./node_modules/mint-tsdocs/lib/schemas/config.schema.json",
- "entryPoint": "dist/index.d.cts",
- "outputFolder": "../../references/common",
+ "entryPoint": "dist/index.d.ts",
+ "outputFolder": "../../docs/references/common",
"lint": {
"eslint": {
"enabled": true
}
+ },
+ "templates": {
+ "userTemplateDir": "../../docs/templates"
}
}
diff --git a/packages/common/package.json b/packages/common/package.json
index ea745156..f101fe67 100644
--- a/packages/common/package.json
+++ b/packages/common/package.json
@@ -54,7 +54,7 @@
"prepack": "pnpm run build && pnpm run lint",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/common/*'",
"release": "cliff-jumper",
- "mint-tsdocs": "mint-tsdocs generate"
+ "docs": "mint-tsdocs generate"
},
"devDependencies": {
"@favware/cliff-jumper": "catalog:ci",
@@ -68,7 +68,7 @@
"unrun": "catalog:build",
"vitest": "catalog:test"
},
- "packageManager": "pnpm@10.33.0",
+ "packageManager": "pnpm@11.5.2",
"engines": {
"node": "25"
},
diff --git a/packages/common/src/common/file.ts b/packages/common/src/common/file.ts
index 27e1eba7..376ac68d 100644
--- a/packages/common/src/common/file.ts
+++ b/packages/common/src/common/file.ts
@@ -1,41 +1,94 @@
import { NfFetchException } from "../exception";
+/**
+ * Represents a file asset that has been registered with the engine.
+ *
+ * @remarks
+ * Instances are returned by `AssetManagerLibrary.getAsset`. Each method
+ * lazily fetches the file from the engine's virtual file system and returns the
+ * content in the requested format.
+ *
+ * All read methods throw `NfFetchException` when the underlying `fetch`
+ * returns a non-OK response.
+ *
+ * @example
+ * ```ts
+ * const file = assetManager.getAsset("/textures/hero.png");
+ * const buffer = await file.arrayBuffer();
+ * ```
+ */
export class NfFile {
private readonly _path: string;
+ /**
+ * @param path - Internal URL path used to fetch the file.
+ */
constructor(path: string) {
this._path = path;
}
+ /**
+ * Internal URL path used to fetch the file.
+ */
get path(): string {
return this._path;
}
+ /**
+ * Fetch the file and return its content as an `ArrayBuffer`.
+ *
+ * @throws `NfFetchException` When the HTTP response is not OK.
+ */
public async arrayBuffer(): Promise {
const res = await this._fetch();
return await res.arrayBuffer();
}
+ /**
+ * Fetch the file and return its content as a `Blob`.
+ *
+ * @throws `NfFetchException` When the HTTP response is not OK.
+ */
public async blob(): Promise {
const res = await this._fetch();
return await res.blob();
}
+ /**
+ * Fetch the file and return its content as a `Uint8Array`.
+ *
+ * @throws `NfFetchException` When the HTTP response is not OK.
+ */
public async bytes(): Promise> {
const res = await this._fetch();
return await res.arrayBuffer().then((buf) => new Uint8Array(buf));
}
+ /**
+ * Fetch the file and return its content as `FormData`.
+ *
+ * @throws `NfFetchException` When the HTTP response is not OK.
+ */
public async formData(): Promise {
const res = await this._fetch();
return await res.formData();
}
+ /**
+ * Fetch the file, parse it as JSON, and return the result.
+ *
+ * @throws `NfFetchException` When the HTTP response is not OK.
+ */
public async json(): Promise {
const res = await this._fetch();
return await res.json();
}
+ /**
+ * Fetch the file and return its content as a UTF-8 string.
+ *
+ * @throws `NfFetchException` When the HTTP response is not OK.
+ */
public async text(): Promise {
const res = await this._fetch();
return await res.text();
diff --git a/packages/common/src/context/contexts/application.context.ts b/packages/common/src/context/contexts/application.context.ts
index d294b16d..96a7f12f 100644
--- a/packages/common/src/context/contexts/application.context.ts
+++ b/packages/common/src/context/contexts/application.context.ts
@@ -1,18 +1,35 @@
+/**
+ * Holds runtime state that is shared across all libraries during the game loop.
+ *
+ * @remarks
+ * An instance of this class is available to every library via
+ * `BaseContext.application`. Libraries may read `isRunning` and `delta`
+ * to make frame-rate-independent decisions.
+ */
export abstract class ApplicationContext {
private _isRunning: boolean = false;
+ /** @internal */
protected _delta!: number;
+ /**
+ * Whether the engine game loop is currently executing.
+ */
get isRunning(): boolean {
return this._isRunning;
}
+ /**
+ * Elapsed time in milliseconds since the last frame.
+ */
get delta(): number {
return this._delta;
}
+ /** @internal */
setIsRunning(value: boolean): void {
this._isRunning = value;
}
+ /** @internal */
abstract muteSoundLibraries(): void;
}
diff --git a/packages/common/src/context/contexts/executions/base.context.ts b/packages/common/src/context/contexts/executions/base.context.ts
index c6917f4d..d5ab9e24 100644
--- a/packages/common/src/context/contexts/executions/base.context.ts
+++ b/packages/common/src/context/contexts/executions/base.context.ts
@@ -1,19 +1,38 @@
import { type LibraryManager } from "../../../library/manager/managers/library.manager";
import { type ApplicationContext } from "../application.context";
+/**
+ * Base context passed to library lifecycle hooks.
+ *
+ * @remarks
+ * All execution context types (`InitContext`, `ClearContext`,
+ * `ExecutionContext`) extend this class and expose `application` and
+ * `libraries`.
+ */
export class BaseContext {
private readonly _applicationContext: ApplicationContext;
private readonly _libraryManager: LibraryManager;
+ /**
+ * @param applicationContext - Shared application-level runtime state.
+ * @param libraryManager - Manager giving access to all registered libraries.
+ */
constructor(applicationContext: ApplicationContext, libraryManager: LibraryManager) {
this._applicationContext = applicationContext;
this._libraryManager = libraryManager;
}
+ /**
+ * Shared application-level runtime state (running flag, delta time, …).
+ */
get application(): ApplicationContext {
return this._applicationContext;
}
+ /**
+ * Manager that provides typed access to every library registered with the
+ * current application.
+ */
get libraries(): LibraryManager {
return this._libraryManager;
}
diff --git a/packages/common/src/context/contexts/executions/clear.context.ts b/packages/common/src/context/contexts/executions/clear.context.ts
index 6755dc87..ba8889a4 100644
--- a/packages/common/src/context/contexts/executions/clear.context.ts
+++ b/packages/common/src/context/contexts/executions/clear.context.ts
@@ -1,3 +1,10 @@
import { BaseContext } from "./base.context";
+/**
+ * Context passed to a library's `__clear` lifecycle hook during application shutdown.
+ *
+ * @remarks
+ * Use the inherited `application` and `libraries` accessors to access shared
+ * state and other libraries while tearing down resources.
+ */
export class ClearContext extends BaseContext {}
diff --git a/packages/common/src/context/contexts/executions/execution.context.ts b/packages/common/src/context/contexts/executions/execution.context.ts
index 7876505c..eae4a5cd 100644
--- a/packages/common/src/context/contexts/executions/execution.context.ts
+++ b/packages/common/src/context/contexts/executions/execution.context.ts
@@ -1,3 +1,10 @@
import { BaseContext } from "./base.context";
+/**
+ * Context passed to a library's `__run` hook on every game-loop tick.
+ *
+ * @remarks
+ * Use the inherited `application` and `libraries` accessors to read the current
+ * delta time and interact with other libraries during the frame update.
+ */
export class ExecutionContext extends BaseContext {}
diff --git a/packages/common/src/context/contexts/executions/init.context.ts b/packages/common/src/context/contexts/executions/init.context.ts
index 7f34ea8f..328771c8 100644
--- a/packages/common/src/context/contexts/executions/init.context.ts
+++ b/packages/common/src/context/contexts/executions/init.context.ts
@@ -3,12 +3,34 @@ import { type IRunClientOptions, type IRunOptions } from "../../../options";
import { type ApplicationContext } from "../application.context";
import { BaseContext } from "./base.context";
+/**
+ * Context object passed to every library's `__init` lifecycle hook.
+ *
+ * @remarks
+ * Provides libraries with all the information they need during start-up:
+ * the canvas container, pre-loaded asset files, environment variables, and a
+ * config registry for loading structured configuration classes.
+ *
+ * Access it in a library's `__init` override:
+ * ```ts
+ * override async __init(ctx: InitContext) {
+ * const config = await ctx.config.registerConfig(MyConfig);
+ * const file = ctx.libraries.getAssetManager().library.getAsset("/data.json");
+ * }
+ * ```
+ */
export class InitContext extends BaseContext {
private readonly _container: IRunClientOptions["container"] | undefined;
private readonly _files: IRunOptions["files"];
private readonly _env: Record;
private readonly _config: IConfigRegistry;
+ /**
+ * @param context - Shared application-level runtime state.
+ * @param libraryManager - Manager giving access to other registered libraries.
+ * @param configRegistry - Registry used to resolve typed configuration objects.
+ * @param options - Run options forwarded from NanoforgeApplication.init.
+ */
constructor(
context: ApplicationContext,
libraryManager: LibraryManager,
@@ -23,18 +45,38 @@ export class InitContext extends BaseContext {
this._config = configRegistry;
}
+ /**
+ * The `HTMLDivElement` that should host the game canvas.
+ *
+ * @remarks
+ * Only available in client contexts; `undefined` on the server.
+ */
get container(): IRunClientOptions["container"] | undefined {
return this._container;
}
+ /**
+ * Map of virtual file paths to their URL strings, pre-loaded by the engine bundler.
+ */
get files(): IRunOptions["files"] {
return this._files;
}
+ /**
+ * Key/value map of environment variables made available at runtime.
+ */
get env(): Record {
return this._env;
}
+ /**
+ * Registry that resolves class-validator/class-transformer decorated
+ * configuration classes from the runtime environment.
+ *
+ * @remarks
+ * Call `ctx.config.registerConfig(MyConfigClass)` to get a validated and
+ * transformed instance populated from `ctx.env`.
+ */
get config(): IConfigRegistry {
return this._config;
}
diff --git a/packages/common/src/context/contexts/library.context.ts b/packages/common/src/context/contexts/library.context.ts
index 711473f8..1b58eb06 100644
--- a/packages/common/src/context/contexts/library.context.ts
+++ b/packages/common/src/context/contexts/library.context.ts
@@ -1,12 +1,25 @@
+/**
+ * Lifecycle states a library can be in.
+ */
export enum LibraryStatusEnum {
+ /** The library has not been initialised yet. */
UNLOADED = "UNLOADED",
+ /** The library has been successfully initialised and is ready to use. */
LOADED = "LOADED",
+ /** The library has been cleared and its resources released. */
CLEAR = "CLEAR",
}
+/**
+ * Tracks the current lifecycle state of a single library registration.
+ */
export class LibraryContext {
+ /** @internal */
protected _status: LibraryStatusEnum = LibraryStatusEnum.UNLOADED;
+ /**
+ * Current lifecycle state of the associated library.
+ */
get status() {
return this._status;
}
diff --git a/packages/common/src/exception/abstracts/exception.abstract.ts b/packages/common/src/exception/abstracts/exception.abstract.ts
index 0857c571..2e6e4985 100644
--- a/packages/common/src/exception/abstracts/exception.abstract.ts
+++ b/packages/common/src/exception/abstracts/exception.abstract.ts
@@ -1,8 +1,32 @@
import type { INfException } from "../interfaces/exception.type";
+/**
+ * Base class for all NanoForge engine exceptions.
+ *
+ * @remarks
+ * All errors thrown by the engine extend this class so that game code can
+ * differentiate engine errors from unrelated runtime errors.
+ *
+ * @example
+ * ```ts
+ * try {
+ * assetManager.getAsset("/missing.png");
+ * } catch (err) {
+ * if (err instanceof NfException) {
+ * console.error(err.code, err.message);
+ * }
+ * }
+ * ```
+ */
export abstract class NfException extends Error implements INfException {
+ /**
+ * HTTP-style numeric code identifying the error category.
+ */
abstract get code(): number;
+ /**
+ * @param message - Optional human-readable description of the error.
+ */
protected constructor(message?: string) {
super(
message ? `[NANOFORGE] ${message}` : "[NANOFORGE] An error occurred (Unknown exception).",
diff --git a/packages/common/src/exception/exceptions/config.exception.ts b/packages/common/src/exception/exceptions/config.exception.ts
index f88f9af6..3f4f4b9e 100644
--- a/packages/common/src/exception/exceptions/config.exception.ts
+++ b/packages/common/src/exception/exceptions/config.exception.ts
@@ -1,10 +1,23 @@
import { NfException } from "../abstracts/exception.abstract";
+/**
+ * Thrown when a library configuration is invalid or incomplete.
+ *
+ * @remarks
+ * Typically raised during `__init` when required environment variables are
+ * missing or fail validation. For example, `NetworkClientLibrary` throws this
+ * when neither `SERVER_TCP_PORT` nor `SERVER_UDP_PORT` is provided.
+ */
export class NfConfigException extends NfException {
+ /** Always `400`. */
get code(): number {
return 400;
}
+ /**
+ * @param message - Description of the configuration error.
+ * @param library - Optional library name that detected the error.
+ */
constructor(message: string, library?: string) {
super(`Config Exception ${library ? `(${library}) ` : ""}- ${message}`);
}
diff --git a/packages/common/src/exception/exceptions/fetch.exception.ts b/packages/common/src/exception/exceptions/fetch.exception.ts
index a37f5eea..35409e6e 100644
--- a/packages/common/src/exception/exceptions/fetch.exception.ts
+++ b/packages/common/src/exception/exceptions/fetch.exception.ts
@@ -1,12 +1,26 @@
import { NfException } from "../abstracts/exception.abstract";
+/**
+ * Thrown when an HTTP fetch performed internally by the engine fails.
+ *
+ * @remarks
+ * Raised by `NfFile` methods (e.g. `arrayBuffer`, `text`) when the
+ * underlying `fetch` call returns a non-OK HTTP response.
+ */
export class NfFetchException extends NfException {
private readonly _code: number;
+ /**
+ * The HTTP status code returned by the failed request (e.g. `404`, `500`).
+ */
get code(): number {
return this._code;
}
+ /**
+ * @param code - HTTP status code of the failed response.
+ * @param text - Status text of the failed response.
+ */
constructor(code: number, text: string) {
super(`Fetch exception : ${code} - ${text}`);
this._code = code;
diff --git a/packages/common/src/exception/exceptions/not-found.exception.ts b/packages/common/src/exception/exceptions/not-found.exception.ts
index 220be27c..57f313e8 100644
--- a/packages/common/src/exception/exceptions/not-found.exception.ts
+++ b/packages/common/src/exception/exceptions/not-found.exception.ts
@@ -1,10 +1,31 @@
import { NfException } from "../abstracts/exception.abstract";
+/**
+ * Thrown when a requested resource (asset, sound, music track, etc.) cannot
+ * be found in the engine's registry.
+ *
+ * @example
+ * ```ts
+ * // Thrown automatically by AssetManagerLibrary.getAsset, SoundLibrary.play, etc.
+ * try {
+ * const file = assetManager.getAsset("/textures/hero.png");
+ * } catch (err) {
+ * if (err instanceof NfNotFound) {
+ * console.error("Missing resource:", err.message);
+ * }
+ * }
+ * ```
+ */
export class NfNotFound extends NfException {
+ /** Always `404`. */
get code(): number {
return 404;
}
+ /**
+ * @param item - Name or path of the missing resource.
+ * @param type - Optional category label (e.g. "Asset", "Sound").
+ */
constructor(item: string, type?: string) {
super(`${type ? `${type} - ` : ""}${item} not found.`);
}
diff --git a/packages/common/src/exception/exceptions/not-initialized.exception.ts b/packages/common/src/exception/exceptions/not-initialized.exception.ts
index 02e3368d..61deec33 100644
--- a/packages/common/src/exception/exceptions/not-initialized.exception.ts
+++ b/packages/common/src/exception/exceptions/not-initialized.exception.ts
@@ -1,10 +1,25 @@
import { NfException } from "../abstracts/exception.abstract";
+/**
+ * Thrown when a method is called on a library or engine component before it
+ * has been initialised via `__init`.
+ *
+ * @remarks
+ * This exception is raised automatically by the helper method
+ * `Library.throwNotInitializedError()`. Ensure that
+ * `NanoforgeApplication.init` has resolved before interacting with any
+ * library.
+ */
export class NfNotInitializedException extends NfException {
+ /** Always `404`. */
get code(): number {
return 404;
}
+ /**
+ * @param item - Name of the uninitialised component (e.g. the library's __name).
+ * @param type - Optional category label (e.g. "Library").
+ */
constructor(item: string, type?: string) {
super(`${type ? `${type} - ` : ""}${item} not initialized.`);
}
diff --git a/packages/common/src/library/config/interfaces/config-registry.type.ts b/packages/common/src/library/config/interfaces/config-registry.type.ts
index 9203201e..875e31a9 100644
--- a/packages/common/src/library/config/interfaces/config-registry.type.ts
+++ b/packages/common/src/library/config/interfaces/config-registry.type.ts
@@ -1,3 +1,36 @@
+/**
+ * Resolves and validates typed configuration objects from the runtime
+ * environment.
+ *
+ * @remarks
+ * An instance is available in `InitContext.config`. Configuration
+ * classes must be decorated with `class-transformer` (`@Expose`, `@Default`)
+ * and `class-validator` (`@IsPort`, `@IsIpOrFQDN`, etc.) decorators from
+ * `@nanoforge-dev/config`.
+ *
+ * @example
+ * ```ts
+ * import `Expose, IsPort ` from "@nanoforge-dev/config";
+ *
+ * class MyConfig {
+ * \@Expose() \@IsPort()
+ * PORT!: string;
+ * }
+ *
+ * // Inside __init:
+ * const cfg = await ctx.config.registerConfig(MyConfig);
+ * console.log(cfg.PORT);
+ * ```
+ */
export interface IConfigRegistry {
+ /**
+ * Instantiate, populate from the runtime environment, transform, and
+ * validate a configuration class.
+ *
+ * @typeParam T - Configuration class type.
+ * @param config - Constructor of the configuration class.
+ * @returns A validated, populated instance of the configuration class.
+ * @throws `NfConfigException` When validation fails.
+ */
registerConfig(config: new () => T): Promise;
}
diff --git a/packages/common/src/library/libraries/abstracts/asset-manager.library.abstract.ts b/packages/common/src/library/libraries/abstracts/asset-manager.library.abstract.ts
index b6fc5df0..6cf813a0 100644
--- a/packages/common/src/library/libraries/abstracts/asset-manager.library.abstract.ts
+++ b/packages/common/src/library/libraries/abstracts/asset-manager.library.abstract.ts
@@ -3,8 +3,25 @@ import { type InitContext } from "../../../context";
import { type IAssetManagerLibrary } from "../interfaces";
import { Library } from "../library";
+/**
+ * Abstract base class for asset-manager libraries.
+ *
+ * @remarks
+ * Extend this class to implement a custom asset-manager and register it with
+ * `NanoforgeApplication.useAssetManager`. The built-in implementation
+ * is `AssetManagerLibrary`.
+ */
export abstract class BaseAssetManagerLibrary extends Library implements IAssetManagerLibrary {
+ /** @internal */
public abstract override __init(context: InitContext): Promise;
+ /**
+ * Retrieve a file asset by its virtual path.
+ *
+ * @param path - Virtual path as registered in the engine's file map (e.g. "/textures/hero.png").
+ * @returns An `NfFile` handle that lazily fetches the asset content.
+ * @throws `NfNotFound` When no asset is registered at the given path.
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
+ */
public abstract getAsset(path: string): NfFile;
}
diff --git a/packages/common/src/library/libraries/abstracts/component-system.library.abstract.ts b/packages/common/src/library/libraries/abstracts/component-system.library.abstract.ts
index 9636529d..a00f9015 100644
--- a/packages/common/src/library/libraries/abstracts/component-system.library.abstract.ts
+++ b/packages/common/src/library/libraries/abstracts/component-system.library.abstract.ts
@@ -2,9 +2,19 @@ import { type Context } from "../../../context";
import { type IComponentSystemLibrary } from "../interfaces";
import { Library } from "../library";
+/**
+ * Abstract base class for component-system (ECS) libraries.
+ *
+ * @remarks
+ * Extend this class (or the higher-level `AbstractECSLibrary`) to
+ * implement a custom ECS back-end and register it with
+ * `NanoforgeApplication.useComponentSystem`. The built-in
+ * implementations are `ECSClientLibrary` and `ECSServerLibrary`.
+ */
export abstract class BaseComponentSystemLibrary
extends Library
implements IComponentSystemLibrary
{
+ /** @internal */
abstract __run(context: Context): Promise;
}
diff --git a/packages/common/src/library/libraries/abstracts/graphics.library.abstract.ts b/packages/common/src/library/libraries/abstracts/graphics.library.abstract.ts
index d26c4b66..ed1baa9b 100644
--- a/packages/common/src/library/libraries/abstracts/graphics.library.abstract.ts
+++ b/packages/common/src/library/libraries/abstracts/graphics.library.abstract.ts
@@ -2,6 +2,15 @@ import { type Context } from "../../../context";
import { type IGraphicsLibrary } from "../interfaces";
import { Library } from "../library";
+/**
+ * Abstract base class for graphics libraries.
+ *
+ * @remarks
+ * Extend this class to implement a custom rendering backend and register it
+ * with `NanoforgeClient.useGraphics`. The built-in implementation is
+ * `Graphics2DLibrary`.
+ */
export abstract class BaseGraphicsLibrary extends Library implements IGraphicsLibrary {
+ /** @internal */
abstract __run(context: Context): Promise;
}
diff --git a/packages/common/src/library/libraries/abstracts/input.library.abstract.ts b/packages/common/src/library/libraries/abstracts/input.library.abstract.ts
index 4befe142..69256a41 100644
--- a/packages/common/src/library/libraries/abstracts/input.library.abstract.ts
+++ b/packages/common/src/library/libraries/abstracts/input.library.abstract.ts
@@ -2,6 +2,15 @@ import { type Context } from "../../../context";
import { type IInputLibrary } from "../interfaces";
import { Library } from "../library";
+/**
+ * Abstract base class for input libraries.
+ *
+ * @remarks
+ * Extend this class to implement a custom input back-end and register it with
+ * `NanoforgeClient.useInput`. The built-in implementation is
+ * `InputLibrary`.
+ */
export abstract class BaseInputLibrary extends Library implements IInputLibrary {
+ /** @internal */
public abstract __run(_context: Context): Promise;
}
diff --git a/packages/common/src/library/libraries/abstracts/music.library.abstract.ts b/packages/common/src/library/libraries/abstracts/music.library.abstract.ts
index 0f197dcf..71614876 100644
--- a/packages/common/src/library/libraries/abstracts/music.library.abstract.ts
+++ b/packages/common/src/library/libraries/abstracts/music.library.abstract.ts
@@ -2,13 +2,31 @@ import { type InitContext } from "../../../context";
import { type IMusicLibrary } from "../interfaces";
import { Library } from "../library";
+/**
+ * Abstract base class for music libraries.
+ *
+ * @remarks
+ * Extend this class to implement a custom music library and register it with
+ * `NanoforgeApplication.use` using the `MUSIC_LIBRARY` symbol.
+ * The built-in implementation is `MusicLibrary`.
+ */
export abstract class BaseMusicLibrary extends Library implements IMusicLibrary {
+ /** @internal */
public abstract override __init(context: InitContext): Promise;
+ /**
+ * Stop the currently playing track (if any) and start playing the requested one.
+ *
+ * @param sound - Key that identifies the music track (as passed to load).
+ * @throws `NfNotFound` When no track is registered under the given key.
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
+ */
public abstract play(sound: string): void;
/**
- * mutes or unmutes the sound.
+ * Toggle the muted state of all loaded music tracks.
+ *
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
*/
public abstract mute(): void;
}
diff --git a/packages/common/src/library/libraries/abstracts/network.library.abstract.ts b/packages/common/src/library/libraries/abstracts/network.library.abstract.ts
index c32ffded..1e793150 100644
--- a/packages/common/src/library/libraries/abstracts/network.library.abstract.ts
+++ b/packages/common/src/library/libraries/abstracts/network.library.abstract.ts
@@ -1,4 +1,12 @@
import { type INetworkLibrary } from "../interfaces";
import { Library } from "../library";
+/**
+ * Abstract base class for network libraries.
+ *
+ * @remarks
+ * Extend this class to implement a custom network library and register it with
+ * `NanoforgeApplication.useNetwork`. The built-in implementations are
+ * `NetworkClientLibrary` and `NetworkServerLibrary`.
+ */
export abstract class BaseNetworkLibrary extends Library implements INetworkLibrary {}
diff --git a/packages/common/src/library/libraries/abstracts/sound.library.abstract.ts b/packages/common/src/library/libraries/abstracts/sound.library.abstract.ts
index 5663f435..7e4ea5cb 100644
--- a/packages/common/src/library/libraries/abstracts/sound.library.abstract.ts
+++ b/packages/common/src/library/libraries/abstracts/sound.library.abstract.ts
@@ -2,13 +2,31 @@ import { type InitContext } from "../../../context";
import { type ISoundLibrary } from "../interfaces";
import { Library } from "../library";
+/**
+ * Abstract base class for sound libraries.
+ *
+ * @remarks
+ * Extend this class to implement a custom sound library and register it with
+ * `NanoforgeClient.useSound`. The built-in implementation is
+ * `SoundLibrary`.
+ */
export abstract class BaseSoundLibrary extends Library implements ISoundLibrary {
+ /** @internal */
public abstract override __init(context: InitContext): Promise;
+ /**
+ * Play a previously loaded sound effect.
+ *
+ * @param sound - Key that identifies the sound (as passed to load).
+ * @throws `NfNotFound` When no sound is registered under the given key.
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
+ */
public abstract play(sound: string): void;
/**
- * mutes or unmutes the sound.
+ * Toggle the muted state of all loaded sound effects.
+ *
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
*/
public abstract mute(): void;
}
diff --git a/packages/common/src/library/libraries/consts/library-label.const.ts b/packages/common/src/library/libraries/consts/library-label.const.ts
index adb3051a..d99b0150 100644
--- a/packages/common/src/library/libraries/consts/library-label.const.ts
+++ b/packages/common/src/library/libraries/consts/library-label.const.ts
@@ -1,7 +1,64 @@
+/**
+ * Registration symbol for the component-system (ECS) library slot.
+ *
+ * @remarks
+ * Pass this symbol to `NanoforgeApplication.use` when registering a
+ * custom component-system library, or use the shorthand
+ * `NanoforgeApplication.useComponentSystem`.
+ */
export const COMPONENT_SYSTEM_LIBRARY = Symbol("COMPONENT_SYSTEM_LIBRARY");
+
+/**
+ * Registration symbol for the graphics library slot.
+ *
+ * @remarks
+ * Pass this symbol to `NanoforgeClient.useGraphics` or use it as a
+ * dependency symbol in a custom library's `ILibraryOptions.dependencies`.
+ */
export const GRAPHICS_LIBRARY = Symbol("GRAPHICS_LIBRARY");
+
+/**
+ * Registration symbol for the network library slot.
+ *
+ * @remarks
+ * Pass this symbol to `NanoforgeApplication.useNetwork` or use it as a
+ * dependency symbol in a custom library's `ILibraryOptions.dependencies`.
+ */
export const NETWORK_LIBRARY = Symbol("NETWORK_LIBRARY");
+
+/**
+ * Registration symbol for the sound library slot.
+ *
+ * @remarks
+ * Pass this symbol to `NanoforgeClient.useSound` or use it as a
+ * dependency symbol in a custom library's `ILibraryOptions.dependencies`.
+ */
export const SOUND_LIBRARY = Symbol("SOUND_LIBRARY");
+
+/**
+ * Registration symbol for the music library slot.
+ *
+ * @remarks
+ * Pass this symbol to `NanoforgeApplication.use` with a custom music
+ * library or use it as a dependency symbol in
+ * `ILibraryOptions.dependencies`.
+ */
export const MUSIC_LIBRARY = Symbol("MUSIC_LIBRARY");
+
+/**
+ * Registration symbol for the asset-manager library slot.
+ *
+ * @remarks
+ * Pass this symbol to `NanoforgeApplication.useAssetManager` or use it
+ * as a dependency in a custom library's `ILibraryOptions.dependencies`.
+ */
export const ASSET_MANAGER_LIBRARY = Symbol("ASSET_MANAGER_LIBRARY");
+
+/**
+ * Registration symbol for the input library slot.
+ *
+ * @remarks
+ * Pass this symbol to `NanoforgeClient.useInput` or use it as a
+ * dependency symbol in a custom library's `ILibraryOptions.dependencies`.
+ */
export const INPUT_LIBRARY = Symbol("INPUT_LIBRARY");
diff --git a/packages/common/src/library/libraries/interfaces/bases/exposed.library.type.ts b/packages/common/src/library/libraries/interfaces/bases/exposed.library.type.ts
index d72f9f1c..fb2d18b6 100644
--- a/packages/common/src/library/libraries/interfaces/bases/exposed.library.type.ts
+++ b/packages/common/src/library/libraries/interfaces/bases/exposed.library.type.ts
@@ -1,3 +1,11 @@
import { type ILibrary } from "../../library.type";
+/**
+ * Marker interface for libraries that are directly accessible to game code via
+ * the `ClientLibraryManager`.
+ *
+ * @remarks
+ * All built-in typed library interfaces (e.g. `IAssetManagerLibrary`,
+ * `ISoundLibrary`) extend this interface.
+ */
export interface IExposedLibrary extends ILibrary {}
diff --git a/packages/common/src/library/libraries/interfaces/bases/mutable.library.type.ts b/packages/common/src/library/libraries/interfaces/bases/mutable.library.type.ts
index f0b52055..aa5aee08 100644
--- a/packages/common/src/library/libraries/interfaces/bases/mutable.library.type.ts
+++ b/packages/common/src/library/libraries/interfaces/bases/mutable.library.type.ts
@@ -1,8 +1,14 @@
import { type ILibrary } from "../../library.type";
+/**
+ * Interface for libraries that support muting/unmuting audio playback.
+ *
+ * @remarks
+ * Implemented by `ISoundLibrary` and `IMusicLibrary`.
+ */
export interface IMutableLibrary extends ILibrary {
/**
- * mutes or unmutes the sound.
+ * Toggle the muted state. Mutes when currently unmuted, and vice versa.
*/
mute(): void;
}
diff --git a/packages/common/src/library/libraries/interfaces/bases/runner.library.type.ts b/packages/common/src/library/libraries/interfaces/bases/runner.library.type.ts
index cf319f32..ac6df49e 100644
--- a/packages/common/src/library/libraries/interfaces/bases/runner.library.type.ts
+++ b/packages/common/src/library/libraries/interfaces/bases/runner.library.type.ts
@@ -1,6 +1,15 @@
import { type Context } from "../../../../context";
import { type ILibrary } from "../../library.type";
+/**
+ * Interface for libraries that participate in the per-frame game loop.
+ *
+ * @remarks
+ * The engine calls `__run` on every tick for all registered runner libraries
+ * in the order determined by their `ILibraryOptions.runBefore` /
+ * `ILibraryOptions.runAfter` relationships.
+ */
export interface IRunnerLibrary extends ILibrary {
+ /** @internal */
__run(context: Context): Promise;
}
diff --git a/packages/common/src/library/libraries/interfaces/finals/asset-manager.library.type.ts b/packages/common/src/library/libraries/interfaces/finals/asset-manager.library.type.ts
index 3f4d7a24..64f1b62f 100644
--- a/packages/common/src/library/libraries/interfaces/finals/asset-manager.library.type.ts
+++ b/packages/common/src/library/libraries/interfaces/finals/asset-manager.library.type.ts
@@ -1,6 +1,21 @@
import { type NfFile } from "../../../../common";
import { type IExposedLibrary } from "../bases/exposed.library.type";
+/**
+ * Interface for asset-manager libraries.
+ *
+ * @remarks
+ * Implemented by `BaseAssetManagerLibrary` and its concrete subclass
+ * `AssetManagerLibrary`. Access an instance via
+ * `ctx.libraries.getAssetManager().library`.
+ */
export interface IAssetManagerLibrary extends IExposedLibrary {
+ /**
+ * Retrieve a registered file asset by its virtual path.
+ *
+ * @param path - Virtual path of the asset (e.g. "/textures/hero.png").
+ * @returns An `NfFile` handle for the requested asset.
+ * @throws `NfNotFound` When no asset is registered at the given path.
+ */
getAsset(path: string): NfFile;
}
diff --git a/packages/common/src/library/libraries/interfaces/finals/component-system.library.type.ts b/packages/common/src/library/libraries/interfaces/finals/component-system.library.type.ts
index 30be76ea..8208b886 100644
--- a/packages/common/src/library/libraries/interfaces/finals/component-system.library.type.ts
+++ b/packages/common/src/library/libraries/interfaces/finals/component-system.library.type.ts
@@ -1,4 +1,13 @@
import { type IExposedLibrary } from "../bases/exposed.library.type";
import { type IRunnerLibrary } from "../bases/runner.library.type";
+/**
+ * Interface for component-system (ECS) libraries.
+ *
+ * @remarks
+ * Implemented by `BaseComponentSystemLibrary` and the higher-level
+ * `AbstractECSLibrary`, with concrete subclasses
+ * `ECSClientLibrary` and `ECSServerLibrary`. Access an instance
+ * via `ctx.libraries.getComponentSystem().library`.
+ */
export interface IComponentSystemLibrary extends IExposedLibrary, IRunnerLibrary {}
diff --git a/packages/common/src/library/libraries/interfaces/finals/graphics.library.type.ts b/packages/common/src/library/libraries/interfaces/finals/graphics.library.type.ts
index 8023a658..9509a9dd 100644
--- a/packages/common/src/library/libraries/interfaces/finals/graphics.library.type.ts
+++ b/packages/common/src/library/libraries/interfaces/finals/graphics.library.type.ts
@@ -1,4 +1,12 @@
import { type IExposedLibrary } from "../bases/exposed.library.type";
import { type IRunnerLibrary } from "../bases/runner.library.type";
+/**
+ * Interface for graphics libraries.
+ *
+ * @remarks
+ * Implemented by `BaseGraphicsLibrary` and its concrete subclass
+ * `Graphics2DLibrary`. Access an instance via
+ * `ctx.libraries.getGraphics().library`.
+ */
export interface IGraphicsLibrary extends IExposedLibrary, IRunnerLibrary {}
diff --git a/packages/common/src/library/libraries/interfaces/finals/input.library.type.ts b/packages/common/src/library/libraries/interfaces/finals/input.library.type.ts
index e01957b4..9dc79452 100644
--- a/packages/common/src/library/libraries/interfaces/finals/input.library.type.ts
+++ b/packages/common/src/library/libraries/interfaces/finals/input.library.type.ts
@@ -1,4 +1,12 @@
import { type IExposedLibrary } from "../bases/exposed.library.type";
import { type IRunnerLibrary } from "../bases/runner.library.type";
+/**
+ * Interface for input libraries.
+ *
+ * @remarks
+ * Implemented by `BaseInputLibrary` and its concrete subclass
+ * `InputLibrary`. Access an instance via
+ * `ctx.libraries.getInput().library`.
+ */
export interface IInputLibrary extends IExposedLibrary, IRunnerLibrary {}
diff --git a/packages/common/src/library/libraries/interfaces/finals/music.library.type.ts b/packages/common/src/library/libraries/interfaces/finals/music.library.type.ts
index 3f469d0a..653e918d 100644
--- a/packages/common/src/library/libraries/interfaces/finals/music.library.type.ts
+++ b/packages/common/src/library/libraries/interfaces/finals/music.library.type.ts
@@ -1,4 +1,12 @@
import { type IExposedLibrary } from "../bases/exposed.library.type";
import { type IMutableLibrary } from "../bases/mutable.library.type";
+/**
+ * Interface for music libraries.
+ *
+ * @remarks
+ * Implemented by `BaseMusicLibrary` and its concrete subclass
+ * `MusicLibrary`. Access an instance via
+ * `ctx.libraries.getMusic().library`.
+ */
export interface IMusicLibrary extends IExposedLibrary, IMutableLibrary {}
diff --git a/packages/common/src/library/libraries/interfaces/finals/network.library.type.ts b/packages/common/src/library/libraries/interfaces/finals/network.library.type.ts
index 4ad23ad5..80d0bca5 100644
--- a/packages/common/src/library/libraries/interfaces/finals/network.library.type.ts
+++ b/packages/common/src/library/libraries/interfaces/finals/network.library.type.ts
@@ -1,3 +1,11 @@
import { type IExposedLibrary } from "../bases/exposed.library.type";
+/**
+ * Interface for network libraries.
+ *
+ * @remarks
+ * Implemented by `BaseNetworkLibrary` and its concrete subclasses
+ * `NetworkClientLibrary` and `NetworkServerLibrary`. Access an
+ * instance via `ctx.libraries.getNetwork().library`.
+ */
export interface INetworkLibrary extends IExposedLibrary {}
diff --git a/packages/common/src/library/libraries/interfaces/finals/sound.library.type.ts b/packages/common/src/library/libraries/interfaces/finals/sound.library.type.ts
index 67141946..8ce0fb79 100644
--- a/packages/common/src/library/libraries/interfaces/finals/sound.library.type.ts
+++ b/packages/common/src/library/libraries/interfaces/finals/sound.library.type.ts
@@ -1,4 +1,12 @@
import { type IExposedLibrary } from "../bases/exposed.library.type";
import { type IMutableLibrary } from "../bases/mutable.library.type";
+/**
+ * Interface for sound-effect libraries.
+ *
+ * @remarks
+ * Implemented by `BaseSoundLibrary` and its concrete subclass
+ * `SoundLibrary`. Access an instance via
+ * `ctx.libraries.getSound().library`.
+ */
export interface ISoundLibrary extends IExposedLibrary, IMutableLibrary {}
diff --git a/packages/common/src/library/libraries/library.ts b/packages/common/src/library/libraries/library.ts
index ec84f4a9..e7624558 100644
--- a/packages/common/src/library/libraries/library.ts
+++ b/packages/common/src/library/libraries/library.ts
@@ -4,9 +4,41 @@ import { RelationshipHandler } from "../relationship/relationship-handler";
import { DEFAULT_LIBRARY_OPTIONS } from "./consts/library-options-default.const";
import { type ILibrary, type ILibraryOptions } from "./library.type";
+/**
+ * Base class for all NanoForge libraries.
+ *
+ * @remarks
+ * Extend this class (or one of its typed subclasses such as
+ * `BaseAssetManagerLibrary`, `BaseSoundLibrary`, etc.) to create a
+ * custom library. At minimum you must implement the `ILibrary.__name`
+ * getter and register the library with the engine before calling
+ * `NanoforgeApplication.init`.
+ *
+ * @example
+ * ```ts
+ * import `Library, type InitContext ` from "@nanoforge-dev/common";
+ *
+ * const MY_LIBRARY = Symbol("MY_LIBRARY");
+ *
+ * class MyLibrary extends Library {
+ * get __name() `return "MyLibrary"; `
+ *
+ * override async __init(ctx: InitContext) {
+ * // one-time setup here
+ * }
+ * }
+ *
+ * const client = NanoforgeFactory.createClient();
+ * client.use(MY_LIBRARY, new MyLibrary());
+ * await client.init(`container, files, env `);
+ * ```
+ */
export abstract class Library implements ILibrary {
protected _relationship: RelationshipHandler;
+ /**
+ * @param rawOptions - Optional dependency and execution-order overrides.
+ */
constructor(rawOptions?: Partial) {
const options = {
...DEFAULT_LIBRARY_OPTIONS,
@@ -20,18 +52,23 @@ export abstract class Library implements ILibrary {
);
}
+ /** @internal */
get __relationship(): RelationshipHandler {
return this._relationship;
}
+ /** @internal */
abstract get __name(): string;
+ /** @internal */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public async __init(_context: InitContext): Promise {}
+ /** @internal */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public async __clear(_context: ClearContext): Promise {}
+ /** @internal */
protected throwNotInitializedError(): never {
throw new NfNotInitializedException(this.__name, "Library");
}
diff --git a/packages/common/src/library/libraries/library.type.ts b/packages/common/src/library/libraries/library.type.ts
index c7f7cf5f..35591bf2 100644
--- a/packages/common/src/library/libraries/library.type.ts
+++ b/packages/common/src/library/libraries/library.type.ts
@@ -1,18 +1,51 @@
import { type ClearContext, type InitContext } from "../../context";
import { type RelationshipHandler } from "../relationship/relationship-handler";
+/**
+ * Core interface that every NanoForge library must satisfy.
+ *
+ * @remarks
+ * Implement this interface (or extend an abstract base such as `BaseAssetManagerLibrary`)
+ * to create a custom library and register it with the engine via
+ * `NanoforgeApplication.use`.
+ */
export interface ILibrary {
+ /** @internal */
get __name(): string;
+ /** @internal */
get __relationship(): RelationshipHandler;
+ /** @internal */
__init(context: InitContext): Promise;
+ /** @internal */
__clear(context: ClearContext): Promise;
}
+/**
+ * Options that control how a library participates in the engine's
+ * initialisation and execution ordering.
+ */
export interface ILibraryOptions {
+ /**
+ * Symbols of libraries that must be fully initialised before this library
+ * can be used.
+ *
+ * @remarks
+ * The engine will reject configurations where a dependency is missing.
+ */
dependencies: symbol[];
+
+ /**
+ * Symbols of libraries whose `__run` method should be called *after* this
+ * library's `__run`.
+ */
runBefore: symbol[];
+
+ /**
+ * Symbols of libraries whose `__run` method must complete *before* this
+ * library's `__run` is invoked.
+ */
runAfter: symbol[];
}
diff --git a/packages/common/src/library/manager/handle/library.handle.ts b/packages/common/src/library/manager/handle/library.handle.ts
index f9fee46b..32bf268c 100644
--- a/packages/common/src/library/manager/handle/library.handle.ts
+++ b/packages/common/src/library/manager/handle/library.handle.ts
@@ -1,25 +1,50 @@
import { type LibraryContext } from "../../../context";
import { type ILibrary } from "../../libraries";
+/**
+ * An opaque handle returned by `LibraryManager` accessors.
+ *
+ * @remarks
+ * Bundles the library instance together with its registration symbol and
+ * lifecycle context. Prefer using the strongly-typed accessor methods on
+ * `LibraryManager` or `ClientLibraryManager` rather than
+ * constructing handles directly.
+ *
+ * @typeParam T - Concrete library type (defaults to `ILibrary`).
+ */
export class LibraryHandle {
private readonly _symbol: symbol;
private readonly _library: T;
private readonly _context: LibraryContext;
+ /**
+ * @param sym - Registration symbol for this library.
+ * @param library - The library instance.
+ * @param defaultContext - Initial lifecycle context.
+ */
constructor(sym: symbol, library: T, defaultContext: LibraryContext) {
this._symbol = sym;
this._library = library;
this._context = defaultContext;
}
+ /**
+ * The registration symbol used to look up this library.
+ */
get symbol(): symbol {
return this._symbol;
}
+ /**
+ * The underlying library instance.
+ */
get library(): T {
return this._library;
}
+ /**
+ * Current lifecycle context tracking the library's status.
+ */
get context(): LibraryContext {
return this._context;
}
diff --git a/packages/common/src/library/manager/managers/client-library.manager.ts b/packages/common/src/library/manager/managers/client-library.manager.ts
index 4dc63b8e..44127935 100644
--- a/packages/common/src/library/manager/managers/client-library.manager.ts
+++ b/packages/common/src/library/manager/managers/client-library.manager.ts
@@ -10,41 +10,95 @@ import {
} from "../../libraries";
import { type LibraryManager } from "./library.manager";
+/**
+ * Convenience wrapper around `LibraryManager` that unwraps
+ * `LibraryHandle` values and returns the library instance directly.
+ *
+ * @remarks
+ * Typically accessed inside a library's lifecycle hooks through the execution
+ * context's `libraries` property after being constructed with a concrete
+ * `LibraryManager`.
+ */
export class ClientLibraryManager {
private readonly _libraryManager: LibraryManager;
+ /**
+ * @param libraryManager - The underlying manager to delegate lookups to.
+ */
constructor(libraryManager: LibraryManager) {
this._libraryManager = libraryManager;
}
+ /**
+ * Retrieve a library registered under a custom symbol.
+ *
+ * @typeParam T - Expected library type.
+ * @param sym - The symbol the library was registered with.
+ * @returns The unwrapped library instance.
+ */
public get(sym: symbol): T {
return this._libraryManager.get(sym).library;
}
+ /**
+ * Retrieve the registered component-system (ECS) library instance.
+ *
+ * @typeParam T - Concrete component-system library type.
+ */
public getComponentSystem(): T {
return this._libraryManager.getComponentSystem().library;
}
+ /**
+ * Retrieve the registered graphics library instance.
+ *
+ * @typeParam T - Concrete graphics library type.
+ */
public getGraphics(): T {
return this._libraryManager.getGraphics().library;
}
+ /**
+ * Retrieve the registered network library instance.
+ *
+ * @typeParam T - Concrete network library type.
+ */
public getNetwork(): T {
return this._libraryManager.getNetwork().library;
}
+ /**
+ * Retrieve the registered input library instance.
+ *
+ * @typeParam T - Concrete input library type.
+ */
public getInput(): T {
return this._libraryManager.getInput().library;
}
+ /**
+ * Retrieve the registered asset-manager library instance.
+ *
+ * @typeParam T - Concrete asset-manager library type.
+ */
public getAssetManager(): T {
return this._libraryManager.getAssetManager().library;
}
+ /**
+ * Retrieve the registered sound library instance.
+ *
+ * @typeParam T - Concrete sound library type.
+ */
public getSound(): T {
return this._libraryManager.getSound().library;
}
+ /**
+ * Retrieve the registered music library instance.
+ *
+ * @typeParam T - Concrete music library type.
+ */
public getMusic(): T {
return this._libraryManager.getMusic().library;
}
diff --git a/packages/common/src/library/manager/managers/library.manager.ts b/packages/common/src/library/manager/managers/library.manager.ts
index 4cdf3abb..22c7df83 100644
--- a/packages/common/src/library/manager/managers/library.manager.ts
+++ b/packages/common/src/library/manager/managers/library.manager.ts
@@ -16,6 +16,14 @@ import {
import { type LibraryHandle } from "../handle/library.handle";
import { BaseLibraryManager } from "./base-library.manager";
+/**
+ * Numeric index keys for the built-in library slots.
+ *
+ * @remarks
+ * Used internally by `LibraryManager` to keep O(1) access to the well-known
+ * library positions. Game code should not reference these values directly —
+ * use the typed accessor methods on `LibraryManager` instead.
+ */
export enum DefaultLibrariesEnum {
ASSET_MANAGER,
COMPONENT_SYSTEM,
@@ -35,6 +43,24 @@ const DEFAULT_LIBRARIES: { index: DefaultLibrariesEnum; sym: symbol }[] = [
{ index: DefaultLibrariesEnum.MUSIC, sym: MUSIC_LIBRARY },
];
+/**
+ * Central registry for all libraries registered with a NanoForge application.
+ *
+ * @remarks
+ * An instance is available inside every lifecycle context via
+ * `BaseContext.libraries`. Use the typed accessor methods to retrieve
+ * any built-in library, or call `BaseLibraryManager.get` with a custom
+ * symbol for user-defined libraries.
+ *
+ * @example
+ * ```ts
+ * // Inside a library's __init hook:
+ * override async __init(ctx: InitContext) {
+ * const assetMgr = ctx.libraries.getAssetManager().library;
+ * const file = assetMgr.getAsset("/data.json");
+ * }
+ * ```
+ */
export class LibraryManager extends BaseLibraryManager {
constructor() {
super();
@@ -44,34 +70,76 @@ export class LibraryManager extends BaseLibraryManager {
}
}
+ /**
+ * Retrieve the registered component-system (ECS) library.
+ *
+ * @typeParam T - Concrete component-system library type.
+ * @returns A `LibraryHandle` wrapping the library instance.
+ */
public getComponentSystem<
T extends IComponentSystemLibrary = IComponentSystemLibrary,
>(): LibraryHandle {
return this._get(DefaultLibrariesEnum.COMPONENT_SYSTEM);
}
+ /**
+ * Retrieve the registered graphics library.
+ *
+ * @typeParam T - Concrete graphics library type.
+ * @returns A `LibraryHandle` wrapping the library instance.
+ */
public getGraphics(): LibraryHandle {
return this._get(DefaultLibrariesEnum.GRAPHICS);
}
+ /**
+ * Retrieve the registered network library.
+ *
+ * @typeParam T - Concrete network library type.
+ * @returns A `LibraryHandle` wrapping the library instance.
+ */
public getNetwork(): LibraryHandle {
return this._get(DefaultLibrariesEnum.NETWORK);
}
+ /**
+ * Retrieve the registered input library.
+ *
+ * @typeParam T - Concrete input library type.
+ * @returns A `LibraryHandle` wrapping the library instance.
+ */
public getInput(): LibraryHandle {
return this._get(DefaultLibrariesEnum.INPUT);
}
+ /**
+ * Retrieve the registered asset-manager library.
+ *
+ * @typeParam T - Concrete asset-manager library type.
+ * @returns A `LibraryHandle` wrapping the library instance.
+ */
public getAssetManager<
T extends IAssetManagerLibrary = IAssetManagerLibrary,
>(): LibraryHandle {
return this._get(DefaultLibrariesEnum.ASSET_MANAGER);
}
+ /**
+ * Retrieve the registered sound library.
+ *
+ * @typeParam T - Concrete sound library type.
+ * @returns A `LibraryHandle` wrapping the library instance.
+ */
public getSound(): LibraryHandle {
return this._get(DefaultLibrariesEnum.SOUND);
}
+ /**
+ * Retrieve the registered music library.
+ *
+ * @typeParam T - Concrete music library type.
+ * @returns A `LibraryHandle` wrapping the library instance.
+ */
public getMusic(): LibraryHandle {
return this._get(DefaultLibrariesEnum.MUSIC);
}
diff --git a/packages/common/src/options/types/options.type.ts b/packages/common/src/options/types/options.type.ts
index 63547da3..b24150ec 100644
--- a/packages/common/src/options/types/options.type.ts
+++ b/packages/common/src/options/types/options.type.ts
@@ -1,12 +1,63 @@
+/**
+ * Union of client and server run options accepted by
+ * `NanoforgeApplication.init`.
+ */
export type IRunOptions = IRunClientOptions | IRunServerOptions;
+/**
+ * Run options for a client-side NanoForge application.
+ *
+ * @remarks
+ * Pass an instance to `NanoforgeApplication.init` when running in the
+ * browser. The engine bundler (`nf build`) automatically generates and
+ * injects `files` and `env` at build time.
+ */
export interface IRunClientOptions {
+ /**
+ * DOM element that will host the game canvas.
+ *
+ * @remarks
+ * The element's current `offsetWidth` and `offsetHeight` are used to set
+ * the initial canvas dimensions.
+ */
container: HTMLDivElement;
+
+ /**
+ * Map of virtual file paths to their resolved URL strings.
+ *
+ * @remarks
+ * Populated automatically by the NanoForge bundler. Keys are normalised
+ * paths such as `"/textures/hero.png"`.
+ */
files: Map;
+
+ /**
+ * Runtime environment variables available to all libraries via
+ * `InitContext.env`.
+ */
env: Record;
}
+/**
+ * Run options for a server-side NanoForge application.
+ *
+ * @remarks
+ * Pass an instance to `NanoforgeApplication.init` when running in a
+ * Node.js server process.
+ */
export interface IRunServerOptions {
+ /**
+ * Map of virtual file paths to their resolved URL strings.
+ *
+ * @remarks
+ * Populated automatically by the NanoForge bundler. Keys are normalised
+ * paths such as `"/data/config.json"`.
+ */
files: Map;
+
+ /**
+ * Runtime environment variables available to all libraries via
+ * `InitContext.env`.
+ */
env: Record;
}
diff --git a/packages/config/README.md b/packages/config/README.md
index db50b756..9f9e3d26 100644
--- a/packages/config/README.md
+++ b/packages/config/README.md
@@ -7,10 +7,9 @@
-
-
+
-
+
diff --git a/packages/config/mint-tsdocs.config.json b/packages/config/mint-tsdocs.config.json
index 819efbed..d68b969c 100644
--- a/packages/config/mint-tsdocs.config.json
+++ b/packages/config/mint-tsdocs.config.json
@@ -1,10 +1,13 @@
{
"$schema": "./node_modules/mint-tsdocs/lib/schemas/config.schema.json",
- "entryPoint": "dist/index.d.cts",
- "outputFolder": "../../references/config",
+ "entryPoint": "dist/index.d.ts",
+ "outputFolder": "../../docs/references/config",
"lint": {
"eslint": {
"enabled": true
}
+ },
+ "templates": {
+ "userTemplateDir": "../../docs/templates"
}
}
diff --git a/packages/config/package.json b/packages/config/package.json
index 650918eb..e2f206b9 100644
--- a/packages/config/package.json
+++ b/packages/config/package.json
@@ -53,7 +53,7 @@
"prepack": "pnpm run build && pnpm run lint",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/config/*'",
"release": "cliff-jumper",
- "mint-tsdocs": "mint-tsdocs generate"
+ "docs": "mint-tsdocs generate"
},
"dependencies": {
"class-transformer": "catalog:config",
@@ -70,7 +70,7 @@
"typescript": "catalog:core",
"unrun": "catalog:build"
},
- "packageManager": "pnpm@10.33.0",
+ "packageManager": "pnpm@11.5.2",
"engines": {
"node": "25"
},
diff --git a/packages/config/src/default.ts b/packages/config/src/default.ts
index f32155c9..ed2a78c3 100644
--- a/packages/config/src/default.ts
+++ b/packages/config/src/default.ts
@@ -1,6 +1,26 @@
import { Transform } from "class-transformer";
import { type TransformFnParams } from "class-transformer/types/interfaces/metadata/transform-fn-params.interface";
+/**
+ * Property decorator that supplies a fallback value when the environment
+ * variable is `undefined` or `null`.
+ *
+ * @remarks
+ * Pairs with `class-transformer`'s `@Expose` and `class-validator` decorators.
+ * The default is deep-cloned via `JSON.parse(JSON.stringify(…))` so objects
+ * are not shared between instances.
+ *
+ * @param defaultValue - The value to use when the property is absent.
+ *
+ * @example
+ * ```ts
+ * class MyConfig {
+ * \@Expose()
+ * \@Default("localhost")
+ * HOST!: string;
+ * }
+ * ```
+ */
export function Default(defaultValue: unknown): PropertyDecorator {
return Transform(
({ value }: TransformFnParams) => value ?? JSON.parse(JSON.stringify(defaultValue)),
diff --git a/packages/config/src/transformers/boolean.transformer.ts b/packages/config/src/transformers/boolean.transformer.ts
index fad1a052..a6ef7a80 100644
--- a/packages/config/src/transformers/boolean.transformer.ts
+++ b/packages/config/src/transformers/boolean.transformer.ts
@@ -6,4 +6,24 @@ const transformStringToBoolean = ({ value }: { value: string }) => {
return undefined;
};
+/**
+ * Property decorator that transforms the string environment variable value
+ * `"true"` or `"false"` into a native `boolean`.
+ *
+ * @remarks
+ * Returns `undefined` for any value that is neither `"true"` nor `"false"`.
+ * Pair with `@IsBoolean()` and `@Default(false)` for a fully validated and
+ * defaulted boolean config property.
+ *
+ * @example
+ * ```ts
+ * class MyConfig {
+ * \@Expose()
+ * \@TransformToBoolean()
+ * \@IsBoolean()
+ * \@Default(false)
+ * FEATURE_FLAG!: boolean;
+ * }
+ * ```
+ */
export const TransformToBoolean = () => Transform(transformStringToBoolean);
diff --git a/packages/config/src/validators/is-ip-or-fqdn.validator.ts b/packages/config/src/validators/is-ip-or-fqdn.validator.ts
index e9cb009a..c7e5d4de 100644
--- a/packages/config/src/validators/is-ip-or-fqdn.validator.ts
+++ b/packages/config/src/validators/is-ip-or-fqdn.validator.ts
@@ -1,5 +1,24 @@
import { type ValidationOptions, isFQDN, isIP, registerDecorator } from "class-validator";
+/**
+ * Property decorator that validates whether the value is a valid IPv4/IPv6
+ * address or a fully qualified domain name (FQDN).
+ *
+ * @remarks
+ * Built on top of `class-validator`'s `isIP` and `isFQDN` helpers. Use on
+ * config properties that represent server hostnames or addresses.
+ *
+ * @param validationOptions - Optional class-validator validation options.
+ *
+ * @example
+ * ```ts
+ * class MyConfig {
+ * \@Expose()
+ * \@IsIpOrFQDN()
+ * SERVER_ADDRESS!: string;
+ * }
+ * ```
+ */
export const IsIpOrFQDN = (validationOptions?: ValidationOptions) => {
return (object: object, propertyName: string) => {
registerDecorator({
diff --git a/packages/core-editor/README.md b/packages/core-editor/README.md
index 19004c8d..89278938 100644
--- a/packages/core-editor/README.md
+++ b/packages/core-editor/README.md
@@ -7,10 +7,9 @@
-
-
+
-
+
diff --git a/packages/core-editor/mint-tsdocs.config.json b/packages/core-editor/mint-tsdocs.config.json
index 411c0442..02fa5cc0 100644
--- a/packages/core-editor/mint-tsdocs.config.json
+++ b/packages/core-editor/mint-tsdocs.config.json
@@ -1,10 +1,13 @@
{
"$schema": "./node_modules/mint-tsdocs/lib/schemas/config.schema.json",
- "entryPoint": "dist/index.d.cts",
- "outputFolder": "../../references/core-editor",
+ "entryPoint": "dist/index.d.ts",
+ "outputFolder": "../../docs/references/core-editor",
"lint": {
"eslint": {
"enabled": true
}
+ },
+ "templates": {
+ "userTemplateDir": "../../docs/templates"
}
}
diff --git a/packages/core-editor/package.json b/packages/core-editor/package.json
index 6fdd6ff7..4b948902 100644
--- a/packages/core-editor/package.json
+++ b/packages/core-editor/package.json
@@ -54,7 +54,7 @@
"prepack": "pnpm run build && pnpm run lint",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/core-editor/*'",
"release": "cliff-jumper",
- "mint-tsdocs": "mint-tsdocs generate"
+ "docs": "mint-tsdocs generate"
},
"dependencies": {
"@nanoforge-dev/asset-manager": "workspace:*",
@@ -76,7 +76,7 @@
"unrun": "catalog:build",
"vitest": "catalog:test"
},
- "packageManager": "pnpm@10.33.0",
+ "packageManager": "pnpm@11.5.2",
"engines": {
"node": "25"
},
diff --git a/packages/core-editor/src/application/nanoforge-application.ts b/packages/core-editor/src/application/nanoforge-application.ts
index 66bb18eb..bef673db 100644
--- a/packages/core-editor/src/application/nanoforge-application.ts
+++ b/packages/core-editor/src/application/nanoforge-application.ts
@@ -12,11 +12,22 @@ import { EditableApplicationContext } from "../../../core/src/common/context/con
import { type IEditorRunOptions } from "../common/context/options.type";
import { Core } from "../core/core";
+/**
+ * Base class for editor-mode NanoForge applications.
+ *
+ * @remarks
+ * Mirror of `NanoforgeApplication` from `@nanoforge-dev/core` with an
+ * extended `init` signature that accepts `IEditorRunOptions`. Use
+ * `NanoforgeFactory` from this package to create instances.
+ */
export abstract class NanoforgeApplication {
protected applicationConfig: ApplicationConfig;
private _core?: Core;
private readonly _options: IApplicationOptions;
+ /**
+ * @param options - Optional application-level settings such as tickRate.
+ */
constructor(options?: Partial) {
this.applicationConfig = new ApplicationConfig();
@@ -26,22 +37,48 @@ export abstract class NanoforgeApplication {
};
}
+ /**
+ * Register a library under a custom symbol.
+ *
+ * @param sym - Unique symbol identifying the library slot.
+ * @param library - Library instance to register.
+ */
public use(sym: symbol, library: ILibrary): void {
this.applicationConfig.useLibrary(sym, library);
}
+ /**
+ * Register the component-system (ECS) library.
+ *
+ * @param library - ECS library instance.
+ */
public useComponentSystem(library: IComponentSystemLibrary) {
this.applicationConfig.useComponentSystemLibrary(library);
}
+ /**
+ * Register the network library.
+ *
+ * @param library - Network library instance.
+ */
public useNetwork(library: INetworkLibrary) {
this.applicationConfig.useNetworkLibrary(library);
}
+ /**
+ * Register the asset-manager library.
+ *
+ * @param library - Asset manager instance.
+ */
public useAssetManager(library: IAssetManagerLibrary) {
this.applicationConfig.useAssetManagerLibrary(library);
}
+ /**
+ * Initialise all registered libraries and prepare the engine for the game loop.
+ *
+ * @param options - Editor run options including save/load callbacks and canvas container.
+ */
public init(options: IEditorRunOptions): Promise {
this._core = new Core(
this.applicationConfig,
@@ -50,6 +87,11 @@ export abstract class NanoforgeApplication {
return this._core.init(options, this._options);
}
+ /**
+ * Start the game loop.
+ *
+ * @throws `NfNotInitializedException` When called before `init`.
+ */
public run() {
if (!this._core) throw new NfNotInitializedException("Core");
return this._core?.run();
diff --git a/packages/core-editor/src/application/nanoforge-client.ts b/packages/core-editor/src/application/nanoforge-client.ts
index 1ddfe4ac..8f799fde 100644
--- a/packages/core-editor/src/application/nanoforge-client.ts
+++ b/packages/core-editor/src/application/nanoforge-client.ts
@@ -6,15 +6,37 @@ import {
import { NanoforgeApplication } from "./nanoforge-application";
+/**
+ * Client-side NanoForge application for editor mode.
+ *
+ * @remarks
+ * Extends `NanoforgeApplication` with graphics, input, and sound library
+ * slots. Create via the `core-editor` `NanoforgeFactory`.
+ */
export class NanoforgeClient extends NanoforgeApplication {
+ /**
+ * Register the graphics library.
+ *
+ * @param library - Graphics library instance (e.g. Graphics2DLibrary).
+ */
public useGraphics(library: IGraphicsLibrary) {
this.applicationConfig.useGraphicsLibrary(library);
}
+ /**
+ * Register the input library.
+ *
+ * @param library - Input library instance (e.g. InputLibrary).
+ */
public useInput(library: IInputLibrary) {
this.applicationConfig.useInputLibrary(library);
}
+ /**
+ * Register the sound-effect library.
+ *
+ * @param library - Sound library instance (e.g. SoundLibrary).
+ */
public useSound(library: ISoundLibrary) {
this.applicationConfig.useSoundLibrary(library);
}
diff --git a/packages/core-editor/src/application/nanoforge-factory.ts b/packages/core-editor/src/application/nanoforge-factory.ts
index 98ec685e..b0599cbf 100644
--- a/packages/core-editor/src/application/nanoforge-factory.ts
+++ b/packages/core-editor/src/application/nanoforge-factory.ts
@@ -3,13 +3,41 @@ import { NanoforgeClient } from "./nanoforge-client";
import { NanoforgeServer } from "./nanoforge-server";
class NanoforgeFactoryStatic {
+ /**
+ * Create a new editor-mode client application.
+ *
+ * @param options - Optional application settings (e.g. tickRate).
+ * @returns A pre-configured `NanoforgeClient` instance.
+ */
createClient(options?: Partial): NanoforgeClient {
return new NanoforgeClient(options);
}
+ /**
+ * Create a new editor-mode server application.
+ *
+ * @param options - Optional application settings (e.g. tickRate).
+ * @returns A pre-configured `NanoforgeServer` instance.
+ */
createServer(options?: Partial): NanoforgeServer {
return new NanoforgeServer(options);
}
}
+/**
+ * Singleton factory for creating editor-mode NanoForge client and server
+ * applications.
+ *
+ * @remarks
+ * Use `NanoforgeFactory.createClient` or
+ * `NanoforgeFactory.createServer` to obtain an application instance that
+ * accepts `IEditorRunOptions` on `init`.
+ *
+ * @example
+ * ```ts
+ * import `NanoforgeFactory ` from "@nanoforge-dev/core-editor";
+ *
+ * const client = NanoforgeFactory.createClient();
+ * ```
+ */
export const NanoforgeFactory = new NanoforgeFactoryStatic();
diff --git a/packages/core-editor/src/application/nanoforge-server.ts b/packages/core-editor/src/application/nanoforge-server.ts
index 74cca8a8..5dfdb20d 100644
--- a/packages/core-editor/src/application/nanoforge-server.ts
+++ b/packages/core-editor/src/application/nanoforge-server.ts
@@ -1,3 +1,10 @@
import { NanoforgeApplication } from "./nanoforge-application";
+/**
+ * Server-side NanoForge application for editor mode.
+ *
+ * @remarks
+ * Extends `NanoforgeApplication` for use in server processes during
+ * editor sessions. Create via the `core-editor` `NanoforgeFactory`.
+ */
export class NanoforgeServer extends NanoforgeApplication {}
diff --git a/packages/core-editor/src/common/context/event-emitter.type.ts b/packages/core-editor/src/common/context/event-emitter.type.ts
index c90caba3..790bddd1 100644
--- a/packages/core-editor/src/common/context/event-emitter.type.ts
+++ b/packages/core-editor/src/common/context/event-emitter.type.ts
@@ -1,24 +1,67 @@
+/**
+ * Events that the NanoForge editor can emit to the running engine.
+ */
export enum EventTypeEnum {
+ /** Reload modules without restarting the engine (live-patch). */
HOT_RELOAD = "hot-reload",
+ /** Fully restart the engine with the latest changes. */
HARD_RELOAD = "hard-reload",
}
+/** Callback signature for event listeners. */
export type ListenerType = (...args: any[]) => void;
+/**
+ * Simple event emitter interface used for communication between the NanoForge
+ * editor and the running engine.
+ *
+ * @remarks
+ * Listeners are queued and processed via `runEvents` to keep the engine
+ * loop deterministic.
+ */
export interface IEventEmitter {
+ /** Map of event names to their registered listeners. */
listeners: Record;
+ /** Queue of events waiting to be dispatched by `runEvents`. */
eventQueue: { event: EventTypeEnum | string; args: any[] }[];
+ /** Drain the event queue and invoke all matching listeners. */
runEvents: () => void;
+ /**
+ * Enqueue an event for dispatching on the next `runEvents` call.
+ *
+ * @param event - Event name or EventTypeEnum value.
+ * @param args - Optional arguments forwarded to listeners.
+ */
emitEvent: (event: EventTypeEnum, ...args: any) => void;
+ /**
+ * Register a listener for an event. Alias: `on`.
+ *
+ * @param event - Event name to subscribe to.
+ * @param listener - Callback invoked when the event fires.
+ */
addListener: (event: EventTypeEnum | string, listener: ListenerType) => void;
+ /** Alias for `addListener`. */
on: (event: EventTypeEnum | string, listener: ListenerType) => void;
+ /**
+ * Remove a previously registered listener. Alias: `off`.
+ *
+ * @param event - Event name to unsubscribe from.
+ * @param listener - The exact listener function to remove.
+ */
removeListener: (event: EventTypeEnum | string, listener: ListenerType) => void;
+ /** Alias for `removeListener`. */
off: (event: EventTypeEnum | string, listener: ListenerType) => void;
+ /**
+ * Remove all listeners registered for a specific event.
+ *
+ * @param event - Event name whose listeners should be cleared.
+ */
removeListenersForEvent: (event: EventTypeEnum | string) => void;
+ /** Remove every registered listener across all events. */
removeAllListeners: () => void;
}
diff --git a/packages/core-editor/src/common/context/options.type.ts b/packages/core-editor/src/common/context/options.type.ts
index 6fde00b6..d8a09fdf 100644
--- a/packages/core-editor/src/common/context/options.type.ts
+++ b/packages/core-editor/src/common/context/options.type.ts
@@ -1,24 +1,54 @@
import { type IEventEmitter } from "./event-emitter.type";
import { type Save } from "./save.type";
+/**
+ * Union of client and server editor run options accepted by
+ * `NanoforgeApplication.init` in editor mode.
+ */
export type IEditorRunOptions = IEditorRunClientOptions | IEditorRunServerOptions;
+/**
+ * Run options for a client-side editor application.
+ *
+ * @remarks
+ * Extends the base run options with editor-specific communication channels.
+ */
export interface IEditorRunClientOptions {
+ /** DOM element that will host the game canvas. */
container: HTMLDivElement;
+ /** Map of virtual file paths to their resolved URL strings. */
files: Map;
+ /** Runtime environment variables available to all libraries. */
env: Record;
+ /** Editor integration hooks. */
editor: {
+ /** Serialised scene state loaded or saved by the editor. */
save: Save;
+ /** Event emitter for core-to-editor communication. */
coreEvents: IEventEmitter;
+ /** Event emitter for editor-to-core communication. */
editorEvents: IEventEmitter;
};
}
+
+/**
+ * Run options for a server-side editor application.
+ *
+ * @remarks
+ * Extends the base server run options with editor-specific communication channels.
+ */
export interface IEditorRunServerOptions {
+ /** Map of virtual file paths to their resolved URL strings. */
files: Map;
+ /** Runtime environment variables available to all libraries. */
env: Record;
+ /** Editor integration hooks. */
editor: {
+ /** Serialised scene state loaded or saved by the editor. */
save: Save;
+ /** Event emitter for core-to-editor communication. */
coreEvents: IEventEmitter;
+ /** Event emitter for editor-to-core communication. */
editorEvents: IEventEmitter;
};
}
diff --git a/packages/core-editor/src/common/context/save.type.ts b/packages/core-editor/src/common/context/save.type.ts
index 36372a33..2337b8bc 100644
--- a/packages/core-editor/src/common/context/save.type.ts
+++ b/packages/core-editor/src/common/context/save.type.ts
@@ -1,3 +1,6 @@
+/**
+ * Identifies the role a library plays in a saved scene.
+ */
export enum SaveLibraryTypeEnum {
COMPONENT_SYSTEM = "component-system",
GRAPHICS = "graphics",
@@ -7,32 +10,62 @@ export enum SaveLibraryTypeEnum {
SOUND = "sound",
}
+/**
+ * Serialised representation of a registered library in a saved scene.
+ */
export interface SaveLibrary {
+ /** Unique identifier for this library instance in the scene. */
id: string;
+ /** Library role (one of `SaveLibraryTypeEnum` or a custom string). */
type: SaveLibraryTypeEnum | string;
+ /** Human-readable name of the library. */
name: string;
+ /** Module path used to import the library at runtime. */
path: string;
}
+/**
+ * Serialised representation of an ECS component type in a saved scene.
+ */
export interface SaveComponent {
+ /** Component class name. */
name: string;
+ /** Module path used to import the component at runtime. */
path: string;
+ /** Names of the constructor parameters exposed in the editor. */
paramsNames: string[];
}
+/**
+ * Serialised representation of an ECS system in a saved scene.
+ */
export interface SaveSystem {
+ /** System class name. */
name: string;
+ /** Module path used to import the system at runtime. */
path: string;
}
+/**
+ * Serialised representation of an entity and its component data.
+ */
export interface SaveEntity {
+ /** Unique identifier for this entity instance. */
id: string;
+ /** Map of component name to its property values. */
components: Record>;
}
+/**
+ * Root serialised scene state exchanged between the editor and the engine.
+ */
export interface Save {
+ /** All libraries registered in the scene. */
libraries: SaveLibrary[];
+ /** All component types available in the scene. */
components: SaveComponent[];
+ /** All systems active in the scene. */
systems: SaveSystem[];
+ /** All spawned entities and their component data. */
entities: SaveEntity[];
}
diff --git a/packages/core/README.md b/packages/core/README.md
index 7bddd539..c6579dfe 100644
--- a/packages/core/README.md
+++ b/packages/core/README.md
@@ -7,10 +7,9 @@
-
-
+
-
+
diff --git a/packages/core/mint-tsdocs.config.json b/packages/core/mint-tsdocs.config.json
index 8e8507c9..e20a2061 100644
--- a/packages/core/mint-tsdocs.config.json
+++ b/packages/core/mint-tsdocs.config.json
@@ -1,10 +1,13 @@
{
"$schema": "./node_modules/mint-tsdocs/lib/schemas/config.schema.json",
- "entryPoint": "dist/index.d.cts",
- "outputFolder": "../../references/core",
+ "entryPoint": "dist/index.d.ts",
+ "outputFolder": "../../docs/references/core",
"lint": {
"eslint": {
"enabled": true
}
+ },
+ "templates": {
+ "userTemplateDir": "../../docs/templates"
}
}
diff --git a/packages/core/package.json b/packages/core/package.json
index 81ad0f04..4758dd4f 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -54,7 +54,7 @@
"prepack": "pnpm run build && pnpm run lint",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/core/*'",
"release": "cliff-jumper",
- "mint-tsdocs": "mint-tsdocs generate"
+ "docs": "mint-tsdocs generate"
},
"dependencies": {
"@nanoforge-dev/asset-manager": "workspace:*",
@@ -75,7 +75,7 @@
"unrun": "catalog:build",
"vitest": "catalog:test"
},
- "packageManager": "pnpm@10.33.0",
+ "packageManager": "pnpm@11.5.2",
"engines": {
"node": "25"
},
diff --git a/packages/core/src/application/application-options.type.ts b/packages/core/src/application/application-options.type.ts
index 57ecc833..071d99ab 100644
--- a/packages/core/src/application/application-options.type.ts
+++ b/packages/core/src/application/application-options.type.ts
@@ -1,3 +1,12 @@
+/**
+ * Options accepted by `NanoforgeFactory.createClient` and
+ * `NanoforgeFactory.createServer`.
+ */
export interface IApplicationOptions {
+ /**
+ * Target game-loop frequency in ticks per second.
+ *
+ * @default 60
+ */
tickRate: number;
}
diff --git a/packages/core/src/application/nanoforge-application.ts b/packages/core/src/application/nanoforge-application.ts
index 7a5fa520..0c650f45 100644
--- a/packages/core/src/application/nanoforge-application.ts
+++ b/packages/core/src/application/nanoforge-application.ts
@@ -12,11 +12,31 @@ import { Core } from "../core/core";
import { ApplicationConfig } from "./application-config";
import type { IApplicationOptions } from "./application-options.type";
+/**
+ * Base class for client and server NanoForge applications.
+ *
+ * @remarks
+ * Do not instantiate directly — use `NanoforgeFactory.createClient` or
+ * `NanoforgeFactory.createServer` to get a fully configured instance of
+ * `NanoforgeClient` or `NanoforgeServer`.
+ *
+ * @example
+ * ```ts
+ * const client = NanoforgeFactory.createClient(`tickRate: 30 `);
+ * client.useAssetManager(new AssetManagerLibrary());
+ * client.useGraphics(new Graphics2DLibrary());
+ * await client.init(`container, files, env `);
+ * client.run();
+ * ```
+ */
export abstract class NanoforgeApplication {
protected applicationConfig: ApplicationConfig;
private _core?: Core;
private readonly _options: IApplicationOptions;
+ /**
+ * @param options - Optional application-level settings such as tickRate.
+ */
constructor(options?: Partial) {
this.applicationConfig = new ApplicationConfig();
@@ -26,22 +46,59 @@ export abstract class NanoforgeApplication {
};
}
+ /**
+ * Register a library under a custom symbol.
+ *
+ * @remarks
+ * Use this method for libraries that do not have a dedicated shorthand (e.g.
+ * game-specific custom libraries). For built-in library types prefer the
+ * typed helpers such as `useAssetManager`, `useNetwork`, etc.
+ *
+ * @param sym - Unique symbol identifying the library slot.
+ * @param library - Library instance to register.
+ */
public use(sym: symbol, library: ILibrary): void {
this.applicationConfig.useLibrary(sym, library);
}
+ /**
+ * Register the component-system (ECS) library.
+ *
+ * @param library - ECS library instance (e.g. ECSClientLibrary or ECSServerLibrary).
+ */
public useComponentSystem(library: IComponentSystemLibrary) {
this.applicationConfig.useComponentSystemLibrary(library);
}
+ /**
+ * Register the network library.
+ *
+ * @param library - Network library instance (e.g. NetworkClientLibrary or NetworkServerLibrary).
+ */
public useNetwork(library: INetworkLibrary) {
this.applicationConfig.useNetworkLibrary(library);
}
+ /**
+ * Register the asset-manager library.
+ *
+ * @param library - Asset manager instance (e.g. AssetManagerLibrary).
+ */
public useAssetManager(library: IAssetManagerLibrary) {
this.applicationConfig.useAssetManagerLibrary(library);
}
+ /**
+ * Initialise all registered libraries in dependency order and prepare the
+ * engine for the game loop.
+ *
+ * @remarks
+ * Must be called before `run`. Resolves once every library's `__init`
+ * hook has completed.
+ *
+ * @param options - Run options providing the canvas container, files map, and
+ * environment variables.
+ */
public init(options: IRunOptions): Promise {
this._core = new Core(
this.applicationConfig,
@@ -50,6 +107,14 @@ export abstract class NanoforgeApplication {
return this._core.init(options, this._options);
}
+ /**
+ * Start the game loop.
+ *
+ * @remarks
+ * Must be called after `init` has resolved.
+ *
+ * @throws `NfNotInitializedException` When called before `init`.
+ */
public run() {
if (!this._core) throw new NfNotInitializedException("Core");
return this._core?.run();
diff --git a/packages/core/src/application/nanoforge-client.ts b/packages/core/src/application/nanoforge-client.ts
index 1ddfe4ac..684e132f 100644
--- a/packages/core/src/application/nanoforge-client.ts
+++ b/packages/core/src/application/nanoforge-client.ts
@@ -6,15 +6,49 @@ import {
import { NanoforgeApplication } from "./nanoforge-application";
+/**
+ * Client-side NanoForge application.
+ *
+ * @remarks
+ * Extends `NanoforgeApplication` with client-specific library slots for
+ * graphics, input, and sound. Create an instance via
+ * `NanoforgeFactory.createClient`.
+ *
+ * @example
+ * ```ts
+ * const client = NanoforgeFactory.createClient();
+ * client.useAssetManager(new AssetManagerLibrary());
+ * client.useGraphics(new Graphics2DLibrary());
+ * client.useInput(new InputLibrary());
+ * client.useSound(new SoundLibrary());
+ * await client.init(`container, files, env `);
+ * client.run();
+ * ```
+ */
export class NanoforgeClient extends NanoforgeApplication {
+ /**
+ * Register the graphics library used to render the game.
+ *
+ * @param library - Graphics library instance (e.g. Graphics2DLibrary).
+ */
public useGraphics(library: IGraphicsLibrary) {
this.applicationConfig.useGraphicsLibrary(library);
}
+ /**
+ * Register the input library used to read keyboard and mouse state.
+ *
+ * @param library - Input library instance (e.g. InputLibrary).
+ */
public useInput(library: IInputLibrary) {
this.applicationConfig.useInputLibrary(library);
}
+ /**
+ * Register the sound-effect library.
+ *
+ * @param library - Sound library instance (e.g. SoundLibrary).
+ */
public useSound(library: ISoundLibrary) {
this.applicationConfig.useSoundLibrary(library);
}
diff --git a/packages/core/src/application/nanoforge-factory.ts b/packages/core/src/application/nanoforge-factory.ts
index 84711a6d..1c275243 100644
--- a/packages/core/src/application/nanoforge-factory.ts
+++ b/packages/core/src/application/nanoforge-factory.ts
@@ -3,13 +3,60 @@ import { NanoforgeClient } from "./nanoforge-client";
import { NanoforgeServer } from "./nanoforge-server";
class NanoforgeFactoryStatic {
+ /**
+ * Create a new client-side NanoForge application.
+ *
+ * @remarks
+ * Returns a `NanoforgeClient` on which you can call
+ * `useGraphics`, `useInput`, `useSound`, `useAssetManager`, etc. before
+ * calling `init` and `run`.
+ *
+ * @param options - Optional application settings (e.g. tickRate).
+ * @returns A pre-configured `NanoforgeClient` instance.
+ *
+ * @example
+ * ```ts
+ * const client = NanoforgeFactory.createClient(`tickRate: 60 `);
+ * ```
+ */
createClient(options?: Partial): NanoforgeClient {
return new NanoforgeClient(options);
}
+ /**
+ * Create a new server-side NanoForge application.
+ *
+ * @remarks
+ * Returns a `NanoforgeServer` on which you can call
+ * `useNetwork`, `useAssetManager`, `useComponentSystem`, etc. before calling
+ * `init` and `run`.
+ *
+ * @param options - Optional application settings (e.g. tickRate).
+ * @returns A pre-configured `NanoforgeServer` instance.
+ *
+ * @example
+ * ```ts
+ * const server = NanoforgeFactory.createServer(`tickRate: 20 `);
+ * ```
+ */
createServer(options?: Partial): NanoforgeServer {
return new NanoforgeServer(options);
}
}
+/**
+ * Singleton factory for creating NanoForge client and server applications.
+ *
+ * @remarks
+ * Use `NanoforgeFactory.createClient` or
+ * `NanoforgeFactory.createServer` to obtain a new application instance,
+ * then attach libraries and call `init` / `run`.
+ *
+ * @example
+ * ```ts
+ * import `NanoforgeFactory ` from "@nanoforge-dev/core";
+ *
+ * const client = NanoforgeFactory.createClient();
+ * ```
+ */
export const NanoforgeFactory = new NanoforgeFactoryStatic();
diff --git a/packages/core/src/application/nanoforge-server.ts b/packages/core/src/application/nanoforge-server.ts
index 74cca8a8..5612515b 100644
--- a/packages/core/src/application/nanoforge-server.ts
+++ b/packages/core/src/application/nanoforge-server.ts
@@ -1,3 +1,20 @@
import { NanoforgeApplication } from "./nanoforge-application";
+/**
+ * Server-side NanoForge application.
+ *
+ * @remarks
+ * Extends `NanoforgeApplication` for use in Node.js server processes.
+ * Create an instance via `NanoforgeFactory.createServer`.
+ *
+ * @example
+ * ```ts
+ * const server = NanoforgeFactory.createServer();
+ * server.useAssetManager(new AssetManagerLibrary());
+ * server.useNetwork(new NetworkServerLibrary());
+ * server.useComponentSystem(new ECSServerLibrary());
+ * await server.init(`files, env `);
+ * server.run();
+ * ```
+ */
export class NanoforgeServer extends NanoforgeApplication {}
diff --git a/packages/ecs-client/README.md b/packages/ecs-client/README.md
index 946e03bc..08a05abb 100644
--- a/packages/ecs-client/README.md
+++ b/packages/ecs-client/README.md
@@ -7,10 +7,9 @@
-
-
+
-
+
diff --git a/packages/ecs-client/mint-tsdocs.config.json b/packages/ecs-client/mint-tsdocs.config.json
index c3949bc2..142757d9 100644
--- a/packages/ecs-client/mint-tsdocs.config.json
+++ b/packages/ecs-client/mint-tsdocs.config.json
@@ -1,10 +1,13 @@
{
"$schema": "./node_modules/mint-tsdocs/lib/schemas/config.schema.json",
- "entryPoint": "dist/index.d.cts",
- "outputFolder": "../../references/ecs-client",
+ "entryPoint": "dist/index.d.ts",
+ "outputFolder": "../../docs/references/ecs-client",
"lint": {
"eslint": {
"enabled": true
}
+ },
+ "templates": {
+ "userTemplateDir": "../../docs/templates"
}
}
diff --git a/packages/ecs-client/package.json b/packages/ecs-client/package.json
index 554030f3..5280b94a 100644
--- a/packages/ecs-client/package.json
+++ b/packages/ecs-client/package.json
@@ -59,7 +59,7 @@
"prepack": "pnpm run build && pnpm run lint",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/ecs-client/*'",
"release": "cliff-jumper",
- "mint-tsdocs": "mint-tsdocs generate"
+ "docs": "mint-tsdocs generate"
},
"dependencies": {
"@nanoforge-dev/common": "workspace:*",
@@ -80,7 +80,7 @@
"unrun": "catalog:build",
"vitest": "catalog:test"
},
- "packageManager": "pnpm@10.33.0",
+ "packageManager": "pnpm@11.5.2",
"engines": {
"node": "25"
},
diff --git a/packages/ecs-client/src/ecs-client-library.ts b/packages/ecs-client/src/ecs-client-library.ts
index 07073a37..a5aaab4a 100644
--- a/packages/ecs-client/src/ecs-client-library.ts
+++ b/packages/ecs-client/src/ecs-client-library.ts
@@ -3,16 +3,35 @@ import { AbstractECSLibrary } from "@nanoforge-dev/ecs-lib";
import { default as Module } from "../lib/libecs";
+/**
+ * Client-side ECS library backed by the compiled WASM module.
+ *
+ * @remarks
+ * Loads `libecs.wasm` from the asset manager and initialises the entity
+ * registry. Register with the application:
+ *
+ * ```ts
+ * client.useComponentSystem(new ECSClientLibrary());
+ * ```
+ *
+ * Access the registry in game code:
+ * ```ts
+ * const ecs = ctx.libraries.getComponentSystem().library;
+ * const entity = ecs.registry.spawnEntity();
+ * ```
+ */
export class ECSClientLibrary extends AbstractECSLibrary {
constructor() {
super();
this.path = "libecs.wasm";
}
+ /** @internal */
get __name(): string {
return "ECSLibrary";
}
+ /** @internal */
override async __init(context: InitContext): Promise {
const wasmFile = context.libraries.getAssetManager().library.getAsset(this.path);
this.module = await Module({ locateFile: () => wasmFile.path });
diff --git a/packages/ecs-lib/README.md b/packages/ecs-lib/README.md
index 4034c004..26e3cb9d 100644
--- a/packages/ecs-lib/README.md
+++ b/packages/ecs-lib/README.md
@@ -7,10 +7,9 @@
-
-
+
-
+
diff --git a/packages/ecs-lib/docs/Doxyfile b/packages/ecs-lib/docs/Doxyfile
deleted file mode 100644
index ac943517..00000000
--- a/packages/ecs-lib/docs/Doxyfile
+++ /dev/null
@@ -1,7 +0,0 @@
-GENERATE_XML = YES
-GENERATE_HTML = NO
-GENERATE_LATEX = NO
-
-INPUT = ../wasm
-
-OUTPUT_DIRECTORY = .
diff --git a/packages/ecs-lib/docs/index.rst b/packages/ecs-lib/docs/index.rst
deleted file mode 100644
index 12c7339a..00000000
--- a/packages/ecs-lib/docs/index.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-ECS Documentation
-=================
-
-.. toctree::
-
-
- wasm.rst
- api/typescript.rst
diff --git a/packages/ecs-lib/docs/typescript.rst b/packages/ecs-lib/docs/typescript.rst
deleted file mode 100644
index 04058040..00000000
--- a/packages/ecs-lib/docs/typescript.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-Typescript
-==========
-
-.. .. js:autoclass:: AbstractECSLibrary
-.. :members:
-
-.. .. js::typealias:: ECSElementDefaults
-.. :members:
diff --git a/packages/ecs-lib/docs/wasm.rst b/packages/ecs-lib/docs/wasm.rst
deleted file mode 100644
index bd9ea6b2..00000000
--- a/packages/ecs-lib/docs/wasm.rst
+++ /dev/null
@@ -1,11 +0,0 @@
-C++ classes
------------
-
-.. doxygenclass:: nfo::Registry
- :members:
-
-.. doxygenclass:: nfo::Entity
- :members:
-
-.. doxygenclass:: nfo::SparseArray
- :members:
diff --git a/packages/ecs-lib/mint-tsdocs.config.json b/packages/ecs-lib/mint-tsdocs.config.json
index c6cbbc4c..c8a98897 100644
--- a/packages/ecs-lib/mint-tsdocs.config.json
+++ b/packages/ecs-lib/mint-tsdocs.config.json
@@ -1,10 +1,13 @@
{
"$schema": "./node_modules/mint-tsdocs/lib/schemas/config.schema.json",
- "entryPoint": "dist/index.d.cts",
- "outputFolder": "../../references/ecs-lib",
+ "entryPoint": "dist/index.d.ts",
+ "outputFolder": "../../docs/references/ecs-lib",
"lint": {
"eslint": {
"enabled": true
}
+ },
+ "templates": {
+ "userTemplateDir": "../../docs/templates"
}
}
diff --git a/packages/ecs-lib/package.json b/packages/ecs-lib/package.json
index 0b434c5b..d45d34ff 100644
--- a/packages/ecs-lib/package.json
+++ b/packages/ecs-lib/package.json
@@ -57,7 +57,7 @@
"prepack": "pnpm run build && pnpm run lint",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/ecs-lib/*'",
"release": "cliff-jumper",
- "mint-tsdocs": "mint-tsdocs generate"
+ "docs": "mint-tsdocs generate"
},
"dependencies": {
"@nanoforge-dev/common": "workspace:*"
@@ -75,7 +75,7 @@
"unrun": "catalog:build",
"vitest": "catalog:test"
},
- "packageManager": "pnpm@10.33.0",
+ "packageManager": "pnpm@11.5.2",
"engines": {
"node": "25"
},
diff --git a/packages/ecs-lib/src/ecs-library.abstract.ts b/packages/ecs-lib/src/ecs-library.abstract.ts
index fa1ebecd..8914aec0 100644
--- a/packages/ecs-lib/src/ecs-library.abstract.ts
+++ b/packages/ecs-lib/src/ecs-library.abstract.ts
@@ -8,12 +8,24 @@ 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}
+ * Abstract base class for WASM-backed ECS (Entity Component System) libraries.
+ *
+ * @remarks
+ * Loads a compiled `libecs.wasm` binary via the asset manager and initialises
+ * a `Registry` from the resulting module. Concrete subclasses only need to
+ * set `this.path` (the asset path to the `.wasm` file) and call `super()`
+ * — see `ECSClientLibrary` and `ECSServerLibrary`.
+ *
+ * Requires the `ASSET_MANAGER_LIBRARY` dependency and runs after
+ * `GRAPHICS_LIBRARY`.
+ *
+ * @example
+ * ```ts
+ * // Inside a system's __run hook:
+ * const ecs = ctx.libraries.getComponentSystem().library;
+ * const player = ecs.registry.spawnEntity();
+ * ecs.registry.addComponent(player, new PositionComponent(0, 0));
+ * ```
*/
export abstract class AbstractECSLibrary extends BaseComponentSystemLibrary {
protected module?: MainModule;
@@ -28,22 +40,23 @@ export abstract class AbstractECSLibrary extends BaseComponentSystemLibrary {
});
}
+ /** @internal */
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.
- */
+ /** @internal */
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.
+ * The WASM-backed entity/component registry.
+ *
+ * @remarks
+ * Use this to spawn entities, register components, add systems, and query
+ * component data.
+ *
+ * @throws `NfNotInitializedException` When accessed before `__init` has resolved.
*/
get registry(): Registry {
if (!this._registry) this.throwNotInitializedError();
diff --git a/packages/ecs-server/README.md b/packages/ecs-server/README.md
index 1682813e..104b97e6 100644
--- a/packages/ecs-server/README.md
+++ b/packages/ecs-server/README.md
@@ -7,10 +7,9 @@
-
-
+
-
+
diff --git a/packages/ecs-server/mint-tsdocs.config.json b/packages/ecs-server/mint-tsdocs.config.json
index fe7a6504..ee0748a4 100644
--- a/packages/ecs-server/mint-tsdocs.config.json
+++ b/packages/ecs-server/mint-tsdocs.config.json
@@ -1,10 +1,13 @@
{
"$schema": "./node_modules/mint-tsdocs/lib/schemas/config.schema.json",
- "entryPoint": "dist/index.d.cts",
- "outputFolder": "../../references/ecs-server",
+ "entryPoint": "dist/index.d.ts",
+ "outputFolder": "../../docs/references/ecs-server",
"lint": {
"eslint": {
"enabled": true
}
+ },
+ "templates": {
+ "userTemplateDir": "../../docs/templates"
}
}
diff --git a/packages/ecs-server/package.json b/packages/ecs-server/package.json
index 32c75cb0..7262cd51 100644
--- a/packages/ecs-server/package.json
+++ b/packages/ecs-server/package.json
@@ -59,7 +59,7 @@
"prepack": "pnpm run build && pnpm run lint",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/ecs-server/*'",
"release": "cliff-jumper",
- "mint-tsdocs": "mint-tsdocs generate"
+ "docs": "mint-tsdocs generate"
},
"dependencies": {
"@nanoforge-dev/common": "workspace:*",
@@ -80,7 +80,7 @@
"unrun": "catalog:build",
"vitest": "catalog:test"
},
- "packageManager": "pnpm@10.33.0",
+ "packageManager": "pnpm@11.5.2",
"engines": {
"node": "25"
},
diff --git a/packages/ecs-server/src/ecs-server-library.ts b/packages/ecs-server/src/ecs-server-library.ts
index ba77c21f..efa17691 100644
--- a/packages/ecs-server/src/ecs-server-library.ts
+++ b/packages/ecs-server/src/ecs-server-library.ts
@@ -3,16 +3,35 @@ import { AbstractECSLibrary } from "@nanoforge-dev/ecs-lib";
import { default as Module } from "../lib/libecs";
+/**
+ * Server-side ECS library backed by the compiled WASM module.
+ *
+ * @remarks
+ * Loads `libecs.wasm` from the asset manager and initialises the entity
+ * registry. Register with the application:
+ *
+ * ```ts
+ * server.useComponentSystem(new ECSServerLibrary());
+ * ```
+ *
+ * Access the registry in game code:
+ * ```ts
+ * const ecs = ctx.libraries.getComponentSystem().library;
+ * const entity = ecs.registry.spawnEntity();
+ * ```
+ */
export class ECSServerLibrary extends AbstractECSLibrary {
constructor() {
super();
this.path = "libecs.wasm";
}
+ /** @internal */
get __name(): string {
return "ECSLibrary";
}
+ /** @internal */
override async __init(context: InitContext): Promise {
const wasmFile = context.libraries.getAssetManager().library.getAsset(this.path);
this.module = await Module({ locateFile: () => wasmFile.path });
diff --git a/packages/graphics-2d/README.md b/packages/graphics-2d/README.md
index 3323f6e9..2781e486 100644
--- a/packages/graphics-2d/README.md
+++ b/packages/graphics-2d/README.md
@@ -7,10 +7,9 @@
-
-
+
-
+
diff --git a/packages/graphics-2d/mint-tsdocs.config.json b/packages/graphics-2d/mint-tsdocs.config.json
index 7a7a6b03..79d49bd5 100644
--- a/packages/graphics-2d/mint-tsdocs.config.json
+++ b/packages/graphics-2d/mint-tsdocs.config.json
@@ -1,10 +1,13 @@
{
"$schema": "./node_modules/mint-tsdocs/lib/schemas/config.schema.json",
- "entryPoint": "dist/index.d.cts",
- "outputFolder": "../../references/graphics-2d",
+ "entryPoint": "dist/index.d.ts",
+ "outputFolder": "../../docs/references/graphics-2d",
"lint": {
"eslint": {
"enabled": true
}
+ },
+ "templates": {
+ "userTemplateDir": "../../docs/templates"
}
}
diff --git a/packages/graphics-2d/package.json b/packages/graphics-2d/package.json
index 1c94a9a3..62d0f722 100644
--- a/packages/graphics-2d/package.json
+++ b/packages/graphics-2d/package.json
@@ -54,7 +54,7 @@
"prepack": "pnpm run build && pnpm run lint",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/graphics-2d/*'",
"release": "cliff-jumper",
- "mint-tsdocs": "mint-tsdocs generate"
+ "docs": "mint-tsdocs generate"
},
"dependencies": {
"@nanoforge-dev/common": "workspace:*",
@@ -72,7 +72,7 @@
"unrun": "catalog:build",
"vitest": "catalog:test"
},
- "packageManager": "pnpm@10.33.0",
+ "packageManager": "pnpm@11.5.2",
"engines": {
"node": "25"
},
diff --git a/packages/graphics-2d/src/exports/konva.ts b/packages/graphics-2d/src/exports/konva.ts
index cbc371b4..77c76cf1 100644
--- a/packages/graphics-2d/src/exports/konva.ts
+++ b/packages/graphics-2d/src/exports/konva.ts
@@ -160,72 +160,107 @@ export type Wedge = Konva.Wedge;
export type WedgeConfig = Konva.WedgeConfig;
+/** @internal */
export const _global = Konva._global;
+/** @internal */
export const _injectGlobal = Konva._injectGlobal;
+/** @internal */
export const _mouseDblClickPointerId = Konva._mouseDblClickPointerId;
+/** @internal */
export const _mouseInDblClickWindow = Konva._mouseInDblClickWindow;
+/** @internal */
export const _mouseListenClick = Konva._mouseListenClick;
+/** @internal */
export const _pointerDblClickPointerId = Konva._pointerDblClickPointerId;
+/** @internal */
export const _pointerInDblClickWindow = Konva._pointerInDblClickWindow;
+/** @internal */
export const _pointerListenClick = Konva._pointerListenClick;
+/** @internal */
export const _renderBackend = Konva._renderBackend;
+/** @internal */
export const _touchDblClickPointerId = Konva._touchDblClickPointerId;
+/** @internal */
export const _touchInDblClickWindow = Konva._touchInDblClickWindow;
+/** @internal */
export const _touchListenClick = Konva._touchListenClick;
+/** @internal */
export const angleDeg = Konva.angleDeg;
+/** @internal */
export const autoDrawEnabled = Konva.autoDrawEnabled;
+/** @internal */
export const capturePointerEventsEnabled = Konva.capturePointerEventsEnabled;
+/** @internal */
export const dblClickWindow = Konva.dblClickWindow;
+/** @internal */
export const document = Konva.document;
+/** @internal */
export const dragButtons = Konva.dragButtons;
+/** @internal */
export const dragDistance = Konva.dragDistance;
+/** @internal */
export const enableTrace = Konva.enableTrace;
+/** @internal */
export const getAngle = Konva.getAngle;
+/** @internal */
export const hitOnDragEnabled = Konva.hitOnDragEnabled;
+/** @internal */
export const isBrowser = Konva.isBrowser;
+/** @internal */
export const isDragReady = Konva.isDragReady;
+/** @internal */
export const isDragging = Konva.isDragging;
+/** @internal */
export const isTransforming = Konva.isTransforming;
+/** @internal */
export const isUnminified = Konva.isUnminified;
+/** @internal */
export const legacyTextRendering = Konva.legacyTextRendering;
+/** @internal */
export const pixelRatio = Konva.pixelRatio;
+/** @internal */
export const pointerEventsEnabled = Konva.pointerEventsEnabled;
+/** @internal */
export const releaseCanvasOnDestroy = Konva.releaseCanvasOnDestroy;
+/** @internal */
export const shapes = Konva.shapes;
+/** @internal */
export const showWarnings = Konva.showWarnings;
+/** @internal */
export const stages = Konva.stages;
+/** @internal */
export const version = Konva.version;
diff --git a/packages/graphics-2d/src/graphics-2d.library.ts b/packages/graphics-2d/src/graphics-2d.library.ts
index 7237cffa..87810256 100644
--- a/packages/graphics-2d/src/graphics-2d.library.ts
+++ b/packages/graphics-2d/src/graphics-2d.library.ts
@@ -2,24 +2,61 @@ import { BaseGraphicsLibrary, type InitContext } from "@nanoforge-dev/common";
import * as Graphics from "./exports/konva";
+/**
+ * Built-in 2D graphics library powered by [Konva](https://konvajs.org/).
+ *
+ * @remarks
+ * Creates a full-window Konva `Stage` and a default `Layer` during
+ * initialisation. Game code interacts with the stage and layer directly to
+ * add shapes, images, and animations. Register with the application:
+ *
+ * ```ts
+ * client.useGraphics(new Graphics2DLibrary());
+ * ```
+ *
+ * Access in game code:
+ * ```ts
+ * const gfx = ctx.libraries.getGraphics().library;
+ * const rect = new Konva.Rect(`x: 10, y: 10, width: 100, height: 50, fill: "red" `);
+ * gfx.baseLayer.add(rect);
+ * ```
+ */
export class Graphics2DLibrary extends BaseGraphicsLibrary {
private _stage?: Graphics.Stage;
private _baseLayer?: Graphics.Layer;
+ /** @internal */
get __name(): string {
return "Graphics2DLibrary";
}
+ /**
+ * The Konva `Stage` that covers the container element.
+ *
+ * @remarks
+ * Initialised to the container's `offsetWidth` × `offsetHeight` dimensions.
+ *
+ * @throws `NfNotInitializedException` When accessed before `__init` has resolved.
+ */
get stage(): Graphics.Stage {
if (!this._stage) this.throwNotInitializedError();
return this._stage;
}
+ /**
+ * The default Konva `Layer` automatically added to the stage.
+ *
+ * @remarks
+ * Add shapes and nodes to this layer for them to appear on screen.
+ *
+ * @throws `NfNotInitializedException` When accessed before `__init` has resolved.
+ */
get baseLayer(): Graphics.Layer {
if (!this._baseLayer) this.throwNotInitializedError();
return this._baseLayer;
}
+ /** @internal */
public override async __init(context: InitContext): Promise {
if (!context.container) {
throw new Error("Can't initialize the container context");
@@ -33,5 +70,6 @@ export class Graphics2DLibrary extends BaseGraphicsLibrary {
this._stage.add(this._baseLayer);
}
+ /** @internal */
public async __run(): Promise {}
}
diff --git a/packages/input/README.md b/packages/input/README.md
index 37f1c75b..8b0d0b41 100644
--- a/packages/input/README.md
+++ b/packages/input/README.md
@@ -7,10 +7,9 @@
-
-
+
-
+
diff --git a/packages/input/mint-tsdocs.config.json b/packages/input/mint-tsdocs.config.json
index 14ab24e0..9d091683 100644
--- a/packages/input/mint-tsdocs.config.json
+++ b/packages/input/mint-tsdocs.config.json
@@ -1,10 +1,13 @@
{
"$schema": "./node_modules/mint-tsdocs/lib/schemas/config.schema.json",
- "entryPoint": "dist/index.d.cts",
- "outputFolder": "../../references/input",
+ "entryPoint": "dist/index.d.ts",
+ "outputFolder": "../../docs/references/input",
"lint": {
"eslint": {
"enabled": true
}
+ },
+ "templates": {
+ "userTemplateDir": "../../docs/templates"
}
}
diff --git a/packages/input/package.json b/packages/input/package.json
index d43566ac..af79aa65 100644
--- a/packages/input/package.json
+++ b/packages/input/package.json
@@ -54,7 +54,7 @@
"prepack": "pnpm run build && pnpm run lint",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/input/*'",
"release": "cliff-jumper",
- "mint-tsdocs": "mint-tsdocs generate"
+ "docs": "mint-tsdocs generate"
},
"dependencies": {
"@nanoforge-dev/common": "workspace:*"
@@ -71,7 +71,7 @@
"unrun": "catalog:build",
"vitest": "catalog:test"
},
- "packageManager": "pnpm@10.33.0",
+ "packageManager": "pnpm@11.5.2",
"engines": {
"node": "25"
},
diff --git a/packages/input/src/input.enum.ts b/packages/input/src/input.enum.ts
index 1cb53165..b52421a1 100644
--- a/packages/input/src/input.enum.ts
+++ b/packages/input/src/input.enum.ts
@@ -1,3 +1,22 @@
+/**
+ * Enumeration of keyboard keys and mouse buttons supported by
+ * `InputLibrary`.
+ *
+ * @remarks
+ * Values correspond to the `KeyboardEvent.code` string for keyboard keys and
+ * to synthetic button identifiers for mouse buttons. Use with
+ * `InputLibrary.isKeyPressed` and `InputLibrary.isDragging`.
+ *
+ * @example
+ * ```ts
+ * if (input.isKeyPressed(InputEnum.Space)) {
+ * player.jump();
+ * }
+ * if (input.isDragging(InputEnum.MouseLeft)) {
+ * camera.pan(input.getDragState());
+ * }
+ * ```
+ */
export enum InputEnum {
Escape = "Escape",
Digit1 = "Digit1",
diff --git a/packages/input/src/input.library.ts b/packages/input/src/input.library.ts
index 103d93f3..4dfb13da 100644
--- a/packages/input/src/input.library.ts
+++ b/packages/input/src/input.library.ts
@@ -4,6 +4,26 @@ import { InputHandler } from "./input-handler";
import { type InputEnum } from "./input.enum";
import { type DragState, type MouseState, type WheelState } from "./mouse.types";
+/**
+ * Built-in input library.
+ *
+ * @remarks
+ * Listens to browser `keydown`, `keyup`, `mousedown`, `mouseup`, `mousemove`,
+ * and `wheel` events and exposes a per-frame snapshot of the current input
+ * state. Must be registered after the graphics library because it uses
+ * `runAfter: [GRAPHICS_LIBRARY]`.
+ *
+ * Register with the application:
+ * ```ts
+ * client.useInput(new InputLibrary());
+ * ```
+ *
+ * Access in a system's `__run` hook:
+ * ```ts
+ * const input = ctx.libraries.getInput().library;
+ * if (input.isKeyPressed(InputEnum.Space)) player.jump();
+ * ```
+ */
export class InputLibrary extends BaseInputLibrary {
private _inputHandler?: InputHandler;
@@ -11,24 +31,41 @@ export class InputLibrary extends BaseInputLibrary {
super({ runAfter: [GRAPHICS_LIBRARY] });
}
+ /** @internal */
get __name(): string {
return "InputLibrary";
}
+ /** @internal */
public override async __init(): Promise {
this._inputHandler = new InputHandler();
}
+ /** @internal */
public override async __run() {
if (!this._inputHandler) this.throwNotInitializedError();
this._inputHandler.resetPerFrame();
}
+ /**
+ * Return whether a key or mouse button is currently held down.
+ *
+ * @param key - The key or button to query (see InputEnum).
+ * @returns `true` when the key is pressed, `false` when released,
+ * `undefined` when the key has never been seen.
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
+ */
public isKeyPressed(key: InputEnum): boolean | undefined {
if (!this._inputHandler) this.throwNotInitializedError();
return this._inputHandler.getKeyStatus(key);
}
+ /**
+ * Return a list of all keys and mouse buttons that are currently pressed.
+ *
+ * @returns Array of `InputEnum` values for all currently-down inputs.
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
+ */
public getPressedKeys(): InputEnum[] {
if (!this._inputHandler) this.throwNotInitializedError();
const res: InputEnum[] = [];
@@ -39,26 +76,61 @@ export class InputLibrary extends BaseInputLibrary {
return res;
}
+ /**
+ * Return the current mouse cursor position.
+ *
+ * @returns Object with `x` and `y` in CSS pixels.
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
+ */
public getMousePosition(): { x: number; y: number } {
if (!this._inputHandler) this.throwNotInitializedError();
return this._inputHandler.getMousePosition();
}
+ /**
+ * Return the full mouse state snapshot for the current frame.
+ *
+ * @returns `MouseState` containing position, previous position, deltas, and focus.
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
+ */
public getMouseState(): MouseState {
if (!this._inputHandler) this.throwNotInitializedError();
return this._inputHandler.mouse;
}
+ /**
+ * Return whether a drag operation is in progress.
+ *
+ * @param button - If provided, only returns true when a drag was started
+ * with this specific button.
+ * @returns `true` when a drag is active (optionally matching the given button).
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
+ */
public isDragging(button?: InputEnum): boolean {
if (!this._inputHandler) this.throwNotInitializedError();
return this._inputHandler.isDragging(button);
}
+ /**
+ * Return the current drag state.
+ *
+ * @returns `DragState` with start position, current position, and deltas.
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
+ */
public getDragState(): DragState {
if (!this._inputHandler) this.throwNotInitializedError();
return this._inputHandler.drag;
}
+ /**
+ * Return the scroll-wheel state accumulated during the current frame.
+ *
+ * @remarks
+ * All deltas are reset to `0` at the start of the next frame.
+ *
+ * @returns `WheelState` with `deltaX`, `deltaY`, and `deltaZ`.
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
+ */
public getWheelState(): WheelState {
if (!this._inputHandler) this.throwNotInitializedError();
return this._inputHandler.wheel;
diff --git a/packages/input/src/mouse.types.ts b/packages/input/src/mouse.types.ts
index b6d95f13..ccc4945a 100644
--- a/packages/input/src/mouse.types.ts
+++ b/packages/input/src/mouse.types.ts
@@ -1,27 +1,70 @@
import { InputEnum } from "./input.enum";
+/**
+ * Snapshot of mouse cursor state for the current frame.
+ *
+ * @remarks
+ * Returned by `InputLibrary.getMouseState`. `deltaX` / `deltaY` are
+ * reset to `0` at the beginning of each frame.
+ */
export type MouseState = {
+ /** Current horizontal cursor position in CSS pixels. */
x: number;
+ /** Current vertical cursor position in CSS pixels. */
y: number;
+ /** Horizontal cursor position from the previous frame. */
prevX: number;
+ /** Vertical cursor position from the previous frame. */
prevY: number;
+ /** Horizontal movement since the previous frame. */
deltaX: number;
+ /** Vertical movement since the previous frame. */
deltaY: number;
+ /** `true` while the cursor is inside the game window. */
focus: boolean;
};
+/**
+ * Snapshot of the current drag operation.
+ *
+ * @remarks
+ * Returned by `InputLibrary.getDragState`. A drag becomes active on
+ * `mousedown` and inactive on `mouseup`.
+ */
export type DragState = {
+ /** `true` when a drag is in progress. */
active: boolean;
+ /** The mouse button that initiated the drag, or `undefined` when inactive. */
button?: InputEnum | undefined;
+ /** Horizontal cursor position when the drag started. */
startX: number;
+ /** Vertical cursor position when the drag started. */
startY: number;
+ /** Current horizontal cursor position during the drag. */
x: number;
+ /** Current vertical cursor position during the drag. */
y: number;
+ /** Total horizontal distance dragged from the start position. */
deltaX: number;
+ /** Total vertical distance dragged from the start position. */
deltaY: number;
};
-export type WheelState = { deltaX: number; deltaY: number; deltaZ: number };
+/**
+ * Snapshot of the scroll wheel state for the current frame.
+ *
+ * @remarks
+ * Returned by `InputLibrary.getWheelState`. All deltas accumulate
+ * within the frame and are reset to `0` at the start of the next frame.
+ */
+export type WheelState = {
+ /** Accumulated horizontal scroll delta. */
+ deltaX: number;
+ /** Accumulated vertical scroll delta. */
+ deltaY: number;
+ /** Accumulated depth (z-axis) scroll delta. */
+ deltaZ: number;
+};
export const MOUSE_BUTTON_MAP: Partial> = {
0: InputEnum.MouseLeft,
diff --git a/packages/music/README.md b/packages/music/README.md
index 543e58d5..6cf40351 100644
--- a/packages/music/README.md
+++ b/packages/music/README.md
@@ -7,10 +7,9 @@
-
-
+
-
+
diff --git a/packages/music/mint-tsdocs.config.json b/packages/music/mint-tsdocs.config.json
index 47ae1054..10ddd89b 100644
--- a/packages/music/mint-tsdocs.config.json
+++ b/packages/music/mint-tsdocs.config.json
@@ -1,10 +1,13 @@
{
"$schema": "./node_modules/mint-tsdocs/lib/schemas/config.schema.json",
- "entryPoint": "dist/index.d.cts",
- "outputFolder": "../../references/music",
+ "entryPoint": "dist/index.d.ts",
+ "outputFolder": "../../docs/references/music",
"lint": {
"eslint": {
"enabled": true
}
+ },
+ "templates": {
+ "userTemplateDir": "../../docs/templates"
}
}
diff --git a/packages/music/package.json b/packages/music/package.json
index 217d3297..58e880f9 100644
--- a/packages/music/package.json
+++ b/packages/music/package.json
@@ -54,7 +54,7 @@
"prepack": "pnpm run build && pnpm run lint",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/music/*'",
"release": "cliff-jumper",
- "mint-tsdocs": "mint-tsdocs generate"
+ "docs": "mint-tsdocs generate"
},
"dependencies": {
"@nanoforge-dev/common": "workspace:*"
@@ -71,7 +71,7 @@
"unrun": "catalog:build",
"vitest": "catalog:test"
},
- "packageManager": "pnpm@10.33.0",
+ "packageManager": "pnpm@11.5.2",
"engines": {
"node": "25"
},
diff --git a/packages/music/src/music.library.ts b/packages/music/src/music.library.ts
index 4c6a0d2c..1a9b904e 100644
--- a/packages/music/src/music.library.ts
+++ b/packages/music/src/music.library.ts
@@ -1,19 +1,45 @@
import { BaseMusicLibrary, NfNotFound } from "@nanoforge-dev/common";
+/**
+ * Built-in music library.
+ *
+ * @remarks
+ * Manages a collection of named `HTMLAudioElement` instances and ensures only
+ * one track plays at a time. Load tracks with `load` and start
+ * playback with `play`. Register with the application:
+ *
+ * ```ts
+ * client.use(MUSIC_LIBRARY, new MusicLibrary());
+ * ```
+ *
+ * Access in game code:
+ * ```ts
+ * const music = ctx.libraries.getMusic().library;
+ * music.load("theme", "/music/main-theme.mp3");
+ * music.play("theme");
+ * ```
+ */
export class MusicLibrary extends BaseMusicLibrary {
private muted: boolean = true;
private musics?: Map;
private current: HTMLAudioElement | null = null;
+ /** @internal */
get __name(): string {
return "NfMusic";
}
+ /** @internal */
public async __init(): Promise {
this.musics = new Map();
this.muted = true;
}
+ /**
+ * Toggle the muted state of all loaded music tracks.
+ *
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
+ */
public mute(): void {
if (!this.musics) this.throwNotInitializedError();
this.muted = !this.muted;
@@ -24,6 +50,13 @@ export class MusicLibrary extends BaseMusicLibrary {
}
}
+ /**
+ * Stop the currently playing track and start the requested one.
+ *
+ * @param music - Key that identifies the track (as passed to load).
+ * @throws `NfNotFound` When no track is registered under the given key.
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
+ */
public play(music: string): void {
if (!this.musics) this.throwNotInitializedError();
const musicElement = this.musics.get(music);
@@ -43,6 +76,17 @@ export class MusicLibrary extends BaseMusicLibrary {
}
}
+ /**
+ * Register a music track under a unique key.
+ *
+ * @remarks
+ * Creates an `HTMLAudioElement` from the provided URL. The track respects
+ * the current muted state at load time.
+ *
+ * @param music - Unique key used to reference this track (e.g. "theme").
+ * @param file - URL or path to the audio file.
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
+ */
public load(music: string, file: string) {
if (!this.musics) this.throwNotInitializedError();
const element = new Audio(file);
diff --git a/packages/network-client/README.md b/packages/network-client/README.md
index 5bb7313e..4c5ee072 100644
--- a/packages/network-client/README.md
+++ b/packages/network-client/README.md
@@ -7,10 +7,9 @@
-
-
+
-
+
diff --git a/packages/network-client/mint-tsdocs.config.json b/packages/network-client/mint-tsdocs.config.json
index f2a10088..f2b37a87 100644
--- a/packages/network-client/mint-tsdocs.config.json
+++ b/packages/network-client/mint-tsdocs.config.json
@@ -1,10 +1,13 @@
{
"$schema": "./node_modules/mint-tsdocs/lib/schemas/config.schema.json",
- "entryPoint": "dist/index.d.cts",
- "outputFolder": "../../references/network-client",
+ "entryPoint": "dist/index.d.ts",
+ "outputFolder": "../../docs/references/network-client",
"lint": {
"eslint": {
"enabled": true
}
+ },
+ "templates": {
+ "userTemplateDir": "../../docs/templates"
}
}
diff --git a/packages/network-client/package.json b/packages/network-client/package.json
index 6fb4eca3..099314dd 100644
--- a/packages/network-client/package.json
+++ b/packages/network-client/package.json
@@ -54,7 +54,7 @@
"prepack": "pnpm run build && pnpm run lint",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/network-client/*'",
"release": "cliff-jumper",
- "mint-tsdocs": "mint-tsdocs generate"
+ "docs": "mint-tsdocs generate"
},
"dependencies": {
"@nanoforge-dev/common": "workspace:*",
@@ -72,7 +72,7 @@
"unrun": "catalog:build",
"vitest": "catalog:test"
},
- "packageManager": "pnpm@10.33.0",
+ "packageManager": "pnpm@11.5.2",
"engines": {
"node": "25"
},
diff --git a/packages/network-client/src/client.network.library.ts b/packages/network-client/src/client.network.library.ts
index 76c98189..a3fade86 100644
--- a/packages/network-client/src/client.network.library.ts
+++ b/packages/network-client/src/client.network.library.ts
@@ -4,17 +4,50 @@ import { ClientConfigNetwork } from "./config.client.network";
import { TCPClient } from "./tcp.client.network";
import { UDPClient } from "./udp.client.network";
+/**
+ * Built-in network library for client-side applications.
+ *
+ * @remarks
+ * Reads network configuration from the environment via
+ * `ClientConfigNetwork` and automatically connects to the server over
+ * TCP (WebSocket), UDP (WebRTC data channel), or both. Register with:
+ *
+ * ```ts
+ * client.useNetwork(new NetworkClientLibrary());
+ * ```
+ *
+ * Configuration (via environment variables):
+ * - `SERVER_ADDRESS` — hostname or IP of the server (required).
+ * - `SERVER_TCP_PORT` — WebSocket port for TCP (optional).
+ * - `SERVER_UDP_PORT` — signaling port for UDP/WebRTC (optional).
+ * - `MAGIC_VALUE` — packet framing delimiter (default: `"PACKET_END"`).
+ * - `WSS` — set to `"true"` to use `wss://` / `https://` (default: `false`).
+ *
+ * After `init`, access the connections via `tcp` and `udp`.
+ */
export class NetworkClientLibrary extends BaseNetworkLibrary {
- // Fast but less reliable send/receive of packets to a UDP server
- public udp!: UDPClient;
-
- // Reliable ordered send/receive of packets to a TCP server
+ /**
+ * Reliable, ordered WebSocket-based connection to the server.
+ *
+ * @remarks
+ * Only available when `SERVER_TCP_PORT` was specified in the environment.
+ */
public tcp!: TCPClient;
+ /**
+ * Unreliable, unordered WebRTC data-channel connection to the server.
+ *
+ * @remarks
+ * Only available when `SERVER_UDP_PORT` was specified in the environment.
+ */
+ public udp!: UDPClient;
+
+ /** @internal */
get __name(): string {
return "NetworkClientLibrary";
}
+ /** @internal */
public override async __init(context: InitContext): Promise {
const config: ClientConfigNetwork = await context.config.registerConfig(ClientConfigNetwork);
diff --git a/packages/network-client/src/config.client.network.ts b/packages/network-client/src/config.client.network.ts
index cbbf1044..5ce77966 100644
--- a/packages/network-client/src/config.client.network.ts
+++ b/packages/network-client/src/config.client.network.ts
@@ -9,26 +9,57 @@ import {
TransformToBoolean,
} from "@nanoforge-dev/config";
+/**
+ * Environment-variable configuration for `NetworkClientLibrary`.
+ *
+ * @remarks
+ * Resolved automatically by `IConfigRegistry.registerConfig` during `__init`.
+ * Set these variables in the environment (or pass them via
+ * `IRunClientOptions.env`) before running the application.
+ */
export class ClientConfigNetwork {
+ /**
+ * Port of the server's TCP WebSocket endpoint.
+ *
+ * @remarks
+ * Either this or `SERVER_UDP_PORT` (or both) must be set.
+ */
@Expose()
@IsOptional()
@IsPort()
SERVER_TCP_PORT?: string;
+ /**
+ * Port of the server's UDP (WebRTC signaling) endpoint.
+ *
+ * @remarks
+ * Either this or `SERVER_TCP_PORT` (or both) must be set.
+ */
@Expose()
@IsOptional()
@IsPort()
SERVER_UDP_PORT?: string;
+ /** Hostname or IP address of the game server. */
@Expose()
@IsIpOrFQDN()
SERVER_ADDRESS!: string;
+ /**
+ * Delimiter bytes appended to each packet for framing.
+ *
+ * @default "PACKET_END"
+ */
@Expose()
@Default("PACKET_END")
@IsByteLength(2, 64)
MAGIC_VALUE!: string;
+ /**
+ * Use secure WebSocket (`wss://`) connections.
+ *
+ * @default false
+ */
@Expose()
@TransformToBoolean()
@IsBoolean()
diff --git a/packages/network-client/src/tcp.client.network.ts b/packages/network-client/src/tcp.client.network.ts
index 35003e26..33073047 100644
--- a/packages/network-client/src/tcp.client.network.ts
+++ b/packages/network-client/src/tcp.client.network.ts
@@ -1,7 +1,15 @@
import { buildMagicPacket, parsePacketsFromChunks } from "./utils";
-/** TCPClient
- * Reliable ordered send/receive of packets to a TCP server
+/**
+ * Reliable, ordered WebSocket-based client connection to a NanoForge TCP server.
+ *
+ * @remarks
+ * Packets are framed with a configurable magic delimiter so that partial
+ * WebSocket frames can be reassembled. The connection is established by
+ * calling `connect` and status can be queried with `isConnected`.
+ *
+ * Typical usage is through `NetworkClientLibrary` which instantiates and
+ * connects this class automatically during `__init`.
*/
export class TCPClient {
private _channel: WebSocket | null = null;
@@ -19,9 +27,12 @@ export class TCPClient {
}
/**
- * Initiate a WebSocket connection to the server (e.g. `ws://:`).
+ * Initiate a WebSocket connection to the server.
*
- * @returns Promise
+ * @remarks
+ * Connects to `ws[s]://:`. Resolves as soon as the connection
+ * attempt is dispatched (the socket may not be fully open yet — check
+ * `isConnected`).
*/
public async connect(): Promise {
this.connectToServerWebSocket();
@@ -29,8 +40,6 @@ export class TCPClient {
/**
* Return `true` when the underlying WebSocket is open.
- *
- * @returns boolean
*/
public isConnected(): boolean {
return this._channel !== null && this._channel.readyState === WebSocket.OPEN;
@@ -39,8 +48,10 @@ export class TCPClient {
/**
* Send a payload to the server.
*
- * @param data Uint8Array — raw payload bytes.
- * @returns void
+ * @remarks
+ * The payload is wrapped in a magic framing packet before being sent.
+ *
+ * @param data - Raw payload bytes.
*/
public sendData(data: Uint8Array): void {
if (!this._channel) {
@@ -51,9 +62,13 @@ export class TCPClient {
}
/**
- * Return an array of complete packets that were reassembled from received chunks.
+ * Parse and return all complete packets received since the last call.
+ *
+ * @remarks
+ * Partial packets are retained internally and combined with future chunks
+ * until they are complete. Call this method once per frame.
*
- * @returns Uint8Array[] — array of packet buffers.
+ * @returns Array of complete packet buffers.
*/
public getReceivedPackets(): Uint8Array[] {
const { packets, data, chunkedData } = parsePacketsFromChunks(
diff --git a/packages/network-client/src/udp.client.network.ts b/packages/network-client/src/udp.client.network.ts
index 3d20e1e6..c15bb0ab 100644
--- a/packages/network-client/src/udp.client.network.ts
+++ b/packages/network-client/src/udp.client.network.ts
@@ -1,7 +1,16 @@
import { buildMagicPacket, parsePacketsFromChunks } from "./utils";
-/** UDPClient
- * Fast but less reliable send/receive of packets to a UDP server
+/**
+ * Unreliable, unordered WebRTC data-channel client connection to a NanoForge
+ * UDP server.
+ *
+ * @remarks
+ * Uses a WebSocket signaling channel to perform the SDP/ICE handshake and then
+ * communicates over an RTCDataChannel with `ordered: false` and
+ * `maxRetransmits: 0` for minimal latency.
+ *
+ * Typical usage is through `NetworkClientLibrary` which instantiates and
+ * connects this class automatically during `__init`.
*/
export class UDPClient {
private _channel: RTCDataChannel | null = null;
@@ -19,9 +28,12 @@ export class UDPClient {
}
/**
- * Open a WebSocket for signaling, create an RTCPeerConnection and initiate an SDP offer.
+ * Open the WebSocket signaling channel, create an RTCPeerConnection, and
+ * complete the SDP/ICE handshake with the server.
*
- * @returns Promise
+ * @remarks
+ * Resolves once the offer has been dispatched. The data channel may become
+ * open shortly after — check `isConnected`.
*/
public async connect(): Promise {
const webSocket: WebSocket = this.connectToServerWebSocket();
@@ -32,8 +44,6 @@ export class UDPClient {
/**
* Return `true` when the RTCDataChannel is open.
- *
- * @returns boolean
*/
public isConnected(): boolean {
return this._channel !== null && this._channel.readyState === "open";
@@ -42,8 +52,10 @@ export class UDPClient {
/**
* Send a payload on the data channel.
*
- * @param data Uint8Array — raw payload bytes.
- * @returns void
+ * @remarks
+ * The payload is wrapped in a magic framing packet before being sent.
+ *
+ * @param data - Raw payload bytes.
*/
public sendData(data: Uint8Array): void {
if (!this._channel) {
@@ -54,9 +66,13 @@ export class UDPClient {
}
/**
- * Return an array of complete packets reassembled from received data-channel chunks.
+ * Parse and return all complete packets received since the last call.
+ *
+ * @remarks
+ * Partial packets are retained internally and combined with future chunks
+ * until they are complete. Call this method once per frame.
*
- * @returns Uint8Array[] — array of packet buffers.
+ * @returns Array of complete packet buffers.
*/
public getReceivedPackets(): Uint8Array[] {
const { packets, data, chunkedData } = parsePacketsFromChunks(
diff --git a/packages/network-server/README.md b/packages/network-server/README.md
index 70de4131..aeb5b00a 100644
--- a/packages/network-server/README.md
+++ b/packages/network-server/README.md
@@ -7,10 +7,9 @@
-
-
+
-
+
diff --git a/packages/network-server/mint-tsdocs.config.json b/packages/network-server/mint-tsdocs.config.json
index 2af3457b..ce8756c1 100644
--- a/packages/network-server/mint-tsdocs.config.json
+++ b/packages/network-server/mint-tsdocs.config.json
@@ -1,10 +1,13 @@
{
"$schema": "./node_modules/mint-tsdocs/lib/schemas/config.schema.json",
- "entryPoint": "dist/index.d.cts",
- "outputFolder": "../../references/network-server",
+ "entryPoint": "dist/index.d.ts",
+ "outputFolder": "../../docs/references/network-server",
"lint": {
"eslint": {
"enabled": true
}
+ },
+ "templates": {
+ "userTemplateDir": "../../docs/templates"
}
}
diff --git a/packages/network-server/package.json b/packages/network-server/package.json
index 10de3887..e2915192 100644
--- a/packages/network-server/package.json
+++ b/packages/network-server/package.json
@@ -54,7 +54,7 @@
"prepack": "pnpm run build && pnpm run lint",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/network-server/*'",
"release": "cliff-jumper",
- "mint-tsdocs": "mint-tsdocs generate"
+ "docs": "mint-tsdocs generate"
},
"dependencies": {
"@mapbox/node-pre-gyp": "catalog:network",
@@ -76,7 +76,7 @@
"unrun": "catalog:build",
"vitest": "catalog:test"
},
- "packageManager": "pnpm@10.33.0",
+ "packageManager": "pnpm@11.5.2",
"engines": {
"node": "25"
},
diff --git a/packages/network-server/src/config.server.network.ts b/packages/network-server/src/config.server.network.ts
index 13923997..b70914df 100644
--- a/packages/network-server/src/config.server.network.ts
+++ b/packages/network-server/src/config.server.network.ts
@@ -8,32 +8,74 @@ import {
IsString,
} from "@nanoforge-dev/config";
+/**
+ * Environment-variable configuration for `NetworkServerLibrary`.
+ *
+ * @remarks
+ * Resolved automatically by `IConfigRegistry.registerConfig` during `__init`.
+ * Set these variables in the environment (or pass them via
+ * `IRunServerOptions.env`) before running the application.
+ */
export class ServerConfigNetwork {
+ /**
+ * Port on which the TCP WebSocket server listens.
+ *
+ * @remarks
+ * Either this or `LISTENING_UDP_PORT` (or both) must be set.
+ */
@Expose()
@IsOptional()
@IsPort()
LISTENING_TCP_PORT?: string;
+ /**
+ * Port on which the UDP (WebRTC signaling) WebSocket server listens.
+ *
+ * @remarks
+ * Either this or `LISTENING_TCP_PORT` (or both) must be set.
+ */
@Expose()
@IsOptional()
@IsPort()
LISTENING_UDP_PORT?: string;
+ /**
+ * Network interface address the server binds to.
+ *
+ * @default "0.0.0.0"
+ */
@Expose()
@Default("0.0.0.0")
@IsIpOrFQDN()
LISTENING_INTERFACE!: string;
+ /**
+ * Delimiter bytes appended to each packet for framing.
+ *
+ * @default "PACKET_END"
+ */
@Expose()
@Default("PACKET_END")
@IsByteLength(2, 64)
MAGIC_VALUE!: string;
+ /**
+ * Path to the TLS certificate file for WSS support.
+ *
+ * @remarks
+ * Must be set together with `WSS_KEY`.
+ */
@Expose()
@IsString()
@IsOptional()
WSS_CERT?: string;
+ /**
+ * Path to the TLS private key file for WSS support.
+ *
+ * @remarks
+ * Must be set together with `WSS_CERT`.
+ */
@Expose()
@IsString()
@IsOptional()
diff --git a/packages/network-server/src/server.network.library.ts b/packages/network-server/src/server.network.library.ts
index c7514b84..a422970d 100644
--- a/packages/network-server/src/server.network.library.ts
+++ b/packages/network-server/src/server.network.library.ts
@@ -4,17 +4,50 @@ import { ServerConfigNetwork } from "./config.server.network";
import { TCPServer } from "./tcp.server.network";
import { UDPServer } from "./udp.server.network";
+/**
+ * Built-in network library for server-side applications.
+ *
+ * @remarks
+ * Reads network configuration from the environment via
+ * `ServerConfigNetwork` and starts TCP (WebSocket) and/or UDP (WebRTC)
+ * servers. Register with:
+ *
+ * ```ts
+ * server.useNetwork(new NetworkServerLibrary());
+ * ```
+ *
+ * Configuration (via environment variables):
+ * - `LISTENING_INTERFACE` — bind address (default: `"0.0.0.0"`).
+ * - `LISTENING_TCP_PORT` — WebSocket listen port for TCP (optional).
+ * - `LISTENING_UDP_PORT` — signaling listen port for UDP (optional).
+ * - `MAGIC_VALUE` — packet framing delimiter (default: `"PACKET_END"`).
+ * - `WSS_CERT` / `WSS_KEY` — paths to TLS certificate and key files for WSS (optional).
+ *
+ * After `init`, access the servers via `tcp` and `udp`.
+ */
export class NetworkServerLibrary extends BaseNetworkLibrary {
- // Fast but less reliable unordered send/receive to multiple UDP clients
+ /**
+ * Unreliable, unordered WebRTC data-channel server for connected clients.
+ *
+ * @remarks
+ * Only available when `LISTENING_UDP_PORT` was specified in the environment.
+ */
public udp!: UDPServer;
- // Reliable ordered send/receive of packets to multiple TCP clients
+ /**
+ * Reliable, ordered WebSocket-based server for connected clients.
+ *
+ * @remarks
+ * Only available when `LISTENING_TCP_PORT` was specified in the environment.
+ */
public tcp!: TCPServer;
+ /** @internal */
get __name(): string {
return "NetworkServerLibrary";
}
+ /** @internal */
public override async __init(context: InitContext): Promise {
const config: ServerConfigNetwork = await context.config.registerConfig(ServerConfigNetwork);
diff --git a/packages/network-server/src/tcp.server.network.ts b/packages/network-server/src/tcp.server.network.ts
index 10e55344..49394d07 100644
--- a/packages/network-server/src/tcp.server.network.ts
+++ b/packages/network-server/src/tcp.server.network.ts
@@ -4,8 +4,17 @@ import { type RawData, type WebSocket, WebSocketServer } from "ws";
import { buildMagicPacket, parsePacketsFromChunks, rawDataToUint8Array } from "./utils";
-/** TCPServer
- * Reliable ordered send/receive of packets to multiple TCP clients
+/**
+ * Reliable, ordered WebSocket-based server that manages multiple TCP clients.
+ *
+ * @remarks
+ * Each client that connects is assigned a numeric ID. Use
+ * `getConnectedClients` to enumerate active clients,
+ * `sendToClient` / `sendToEverybody` to push data, and
+ * `getReceivedPackets` to consume incoming packets per frame.
+ *
+ * Typical usage is through `NetworkServerLibrary` which instantiates and
+ * starts this class automatically during `__init`.
*/
export class TCPServer {
private _clients = new Map<
diff --git a/packages/network-server/src/udp.server.network.ts b/packages/network-server/src/udp.server.network.ts
index fd1eaea4..c8dad07c 100644
--- a/packages/network-server/src/udp.server.network.ts
+++ b/packages/network-server/src/udp.server.network.ts
@@ -5,8 +5,19 @@ import { type RawData, type WebSocket, WebSocketServer } from "ws";
import { buildMagicPacket, parsePacketsFromChunks } from "./utils";
-/** UDPServer
- * Fast but less reliable unordered send/receive to multiple UDP clients
+/**
+ * Unreliable, unordered WebRTC data-channel server that manages multiple UDP
+ * clients.
+ *
+ * @remarks
+ * Uses a WebSocket signaling server to complete SDP/ICE handshakes and then
+ * communicates over RTCDataChannels. Each connected client is assigned a
+ * numeric ID. Use `getConnectedClients` to enumerate active clients,
+ * `sendToClient` / `sendToEverybody` to push data, and
+ * `getReceivedPackets` to consume incoming packets per frame.
+ *
+ * Typical usage is through `NetworkServerLibrary` which instantiates and
+ * starts this class automatically during `__init`.
*/
export class UDPServer {
private _clients = new Map<
@@ -109,7 +120,7 @@ export class UDPServer {
* The packet will be framed with the server's configured magic terminator
* bytes before being sent.
*
- * @param clientId - Numeric client identifier returned by `listen()` events
+ * @param clientId - Numeric client identifier returned by listen() events
* @param data - Raw packet bytes (Uint8Array) to send
* @returns void
*/
diff --git a/packages/sound/README.md b/packages/sound/README.md
index 93bbc8c2..63e83f28 100644
--- a/packages/sound/README.md
+++ b/packages/sound/README.md
@@ -7,10 +7,9 @@
-
-
+
-
+
diff --git a/packages/sound/mint-tsdocs.config.json b/packages/sound/mint-tsdocs.config.json
index c5b9faee..f28a3e8a 100644
--- a/packages/sound/mint-tsdocs.config.json
+++ b/packages/sound/mint-tsdocs.config.json
@@ -1,10 +1,13 @@
{
"$schema": "./node_modules/mint-tsdocs/lib/schemas/config.schema.json",
- "entryPoint": "dist/index.d.cts",
- "outputFolder": "../../references/sound",
+ "entryPoint": "dist/index.d.ts",
+ "outputFolder": "../../docs/references/sound",
"lint": {
"eslint": {
"enabled": true
}
+ },
+ "templates": {
+ "userTemplateDir": "../../docs/templates"
}
}
diff --git a/packages/sound/package.json b/packages/sound/package.json
index 434d2ebd..4c7b3b23 100644
--- a/packages/sound/package.json
+++ b/packages/sound/package.json
@@ -54,7 +54,7 @@
"prepack": "pnpm run build && pnpm run lint",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/sound/*'",
"release": "cliff-jumper",
- "mint-tsdocs": "mint-tsdocs generate"
+ "docs": "mint-tsdocs generate"
},
"dependencies": {
"@nanoforge-dev/common": "workspace:*"
@@ -71,7 +71,7 @@
"unrun": "catalog:build",
"vitest": "catalog:test"
},
- "packageManager": "pnpm@10.33.0",
+ "packageManager": "pnpm@11.5.2",
"engines": {
"node": "25"
},
diff --git a/packages/sound/src/sound.library.ts b/packages/sound/src/sound.library.ts
index 986db947..1fd753d9 100644
--- a/packages/sound/src/sound.library.ts
+++ b/packages/sound/src/sound.library.ts
@@ -1,18 +1,44 @@
import { BaseSoundLibrary, NfNotFound } from "@nanoforge-dev/common";
+/**
+ * Built-in sound-effect library.
+ *
+ * @remarks
+ * Manages a collection of named `HTMLAudioElement` instances. Load sounds
+ * with `load` and trigger playback with `play`. Register with
+ * the application:
+ *
+ * ```ts
+ * client.useSound(new SoundLibrary());
+ * ```
+ *
+ * Access in game code:
+ * ```ts
+ * const sound = ctx.libraries.getSound().library;
+ * sound.load("explosion", "/sounds/explosion.mp3");
+ * sound.play("explosion");
+ * ```
+ */
export class SoundLibrary extends BaseSoundLibrary {
private muted: boolean = true;
private sounds?: Map;
+ /** @internal */
get __name(): string {
return "NfSound";
}
+ /** @internal */
public async __init(): Promise {
this.sounds = new Map();
this.muted = true;
}
+ /**
+ * Toggle the muted state of all loaded sound effects.
+ *
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
+ */
public mute(): void {
if (!this.sounds) this.throwNotInitializedError();
this.muted = !this.muted;
@@ -23,6 +49,13 @@ export class SoundLibrary extends BaseSoundLibrary {
}
}
+ /**
+ * Play a previously loaded sound effect.
+ *
+ * @param sound - Key that identifies the sound (as passed to load).
+ * @throws `NfNotFound` When no sound is registered under the given key.
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
+ */
public play(sound: string): void {
if (!this.sounds) this.throwNotInitializedError();
const soundElement = this.sounds.get(sound);
@@ -39,6 +72,17 @@ export class SoundLibrary extends BaseSoundLibrary {
}
}
+ /**
+ * Register a sound effect under a unique key.
+ *
+ * @remarks
+ * Creates an `HTMLAudioElement` from the provided URL. The sound respects
+ * the current muted state at load time.
+ *
+ * @param sound - Unique key used to reference this sound (e.g. "explosion").
+ * @param file - URL or path to the audio file.
+ * @throws `NfNotInitializedException` When called before `__init` has resolved.
+ */
public load(sound: string, file: string) {
if (!this.sounds) this.throwNotInitializedError();
const element = new Audio(file);
diff --git a/scripts/sync-docs-references.sh b/scripts/sync-docs-references.sh
new file mode 100755
index 00000000..75463387
--- /dev/null
+++ b/scripts/sync-docs-references.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+ROOT="$SCRIPT_DIR/.."
+REFS="$ROOT/docs/references"
+PKGS="$ROOT/packages"
+
+for pkg_dir in "$REFS"/*/; do
+ pkg="$(basename "$pkg_dir")"
+
+ # skip non-package entries
+ [[ "$pkg" == "snippets" ]] && continue
+ [[ ! -d "$PKGS/$pkg" ]] && continue
+
+ inner="$REFS/$pkg/$pkg"
+ [[ ! -d "$inner" ]] && continue
+
+ echo "Processing: $pkg"
+
+ # delete everything in docs/references/ except the / subdirectory
+ find "$REFS/$pkg" -mindepth 1 -maxdepth 1 ! -name "$pkg" -exec rm -rf {} +
+
+ # copy the contents of docs/references/// into docs/references//
+ cp -r "$inner"/. "$REFS/$pkg/"
+
+ # remove the now-redundant inner directory
+ rm -rf "$inner"
+
+ # copy packages//README.md as 0-index.mdx with a Mintlify title frontmatter
+ readme="$PKGS/$pkg/README.md"
+ if [[ -f "$readme" ]]; then
+ title="$(echo "$pkg" | sed 's/-/ /g; s/\b\(.\)/\u\1/g')"
+ { printf -- '---\ntitle: "%s"\n---\n\n' "$title"; cat "$readme"; } > "$REFS/$pkg/0-index.mdx"
+ else
+ echo " WARNING: no README.md found for $pkg"
+ fi
+done
+
+echo "Done."
\ No newline at end of file
diff --git a/turbo.json b/turbo.json
index 4a11ab4f..ee6450f8 100644
--- a/turbo.json
+++ b/turbo.json
@@ -43,17 +43,18 @@
"outputs": [],
"outputLogs": "errors-only"
},
- "mint-tsdocs": {
- "dependsOn": ["^mint-tsdocs"],
+ "docs": {
+ "dependsOn": ["^docs"],
"inputs": [
"src/**",
"wasm/**",
"test/**",
"package.json",
"tsconfig.json",
- "mint-tsdocs.config.ts"
+ "mint-tsdocs.config.ts",
+ "../../docs/templates/**"
],
- "outputs": ["../../references"],
+ "outputs": ["../../docs/references/**"],
"outputLogs": "errors-only"
}
}
diff --git a/utils/eslint-config/README.md b/utils/eslint-config/README.md
index e82c032e..107d53c5 100644
--- a/utils/eslint-config/README.md
+++ b/utils/eslint-config/README.md
@@ -7,10 +7,9 @@
-
-
+
-
+
diff --git a/utils/eslint-config/package.json b/utils/eslint-config/package.json
index 92306c86..25790056 100644
--- a/utils/eslint-config/package.json
+++ b/utils/eslint-config/package.json
@@ -58,7 +58,7 @@
"eslint": "catalog:lint",
"prettier": "catalog:lint"
},
- "packageManager": "pnpm@10.33.0",
+ "packageManager": "pnpm@11.5.2",
"engines": {
"node": "25"
},
diff --git a/utils/prettier-config/README.md b/utils/prettier-config/README.md
index 1705c838..b381f4f6 100644
--- a/utils/prettier-config/README.md
+++ b/utils/prettier-config/README.md
@@ -7,10 +7,9 @@
-
-
+
-
+
diff --git a/utils/prettier-config/package.json b/utils/prettier-config/package.json
index 3a86d25e..e05118a0 100644
--- a/utils/prettier-config/package.json
+++ b/utils/prettier-config/package.json
@@ -47,7 +47,7 @@
"@trivago/prettier-plugin-sort-imports": "catalog:lint",
"prettier": "catalog:lint"
},
- "packageManager": "pnpm@10.33.0",
+ "packageManager": "pnpm@11.5.2",
"engines": {
"node": "25"
},