From ad2b8e89724c137b1a8a360ab20e4201e2fbbc21 Mon Sep 17 00:00:00 2001 From: Exelo Date: Sat, 12 Sep 2026 16:26:21 +0200 Subject: [PATCH] feat: add ecs editor manifest types --- modules/ecs/README.md | 14 +- modules/ecs/package.json | 16 +- modules/ecs/src/index.ts | 6 + .../ecs/src/shared/editor-manifest.type.ts | 142 ++++++++++++++++++ modules/ecs/tsdown.config.ts | 1 + 5 files changed, 175 insertions(+), 4 deletions(-) create mode 100644 modules/ecs/src/index.ts create mode 100644 modules/ecs/src/shared/editor-manifest.type.ts diff --git a/modules/ecs/README.md b/modules/ecs/README.md index d92b47e1..3aae83fa 100644 --- a/modules/ecs/README.md +++ b/modules/ecs/README.md @@ -15,7 +15,7 @@ ## About -`@nanoforge-dev/ecs` is NanoForge's built-in entity-component-system library, backed by a WebAssembly registry (compiled from C++). It ships two subpath entry points — `@nanoforge-dev/ecs/client` and `@nanoforge-dev/ecs/server` — each loading its own WASM build (browser-targeted vs Node-targeted) behind the same `EcsLibrary` API, so a client bundle never pulls in the server build or vice versa. +`@nanoforge-dev/ecs` is NanoForge's built-in entity-component-system library, backed by a WebAssembly registry (compiled from C++). It ships two subpath entry points — `@nanoforge-dev/ecs/client` and `@nanoforge-dev/ecs/server` — each loading its own WASM build (browser-targeted vs Node-targeted) behind the same `EcsLibrary` API, so a client bundle never pulls in the server build or vice versa. The root entry point, `@nanoforge-dev/ecs`, only exposes the shared types (`Registry`, `Component`, `System`, `Entity`, `SparseArray`, `Context`, `EcsContextApi`) and pulls in no WASM binary, so it's safe to import from code that targets both client and server. ## Installation @@ -46,6 +46,18 @@ import { EcsLibrary } from "@nanoforge-dev/ecs/server"; app.use(new EcsLibrary()); ``` +Shared types like `Registry`, `Component`, and `System` are available from the root entry point, regardless of which platform you're targeting: + +```ts +import type { Component, Context, Registry, System } from "@nanoforge-dev/ecs"; + +const Position: Component = { name: "Position" }; + +const gravity: System = (registry: Registry, ctx: Context) => { + // ... +}; +``` + Once registered, `Context.ecs.registry` gives every other library access to the entity/component registry: ```ts diff --git a/modules/ecs/package.json b/modules/ecs/package.json index dfdd22cc..1a47064f 100644 --- a/modules/ecs/package.json +++ b/modules/ecs/package.json @@ -21,10 +21,20 @@ "files": [ "dist" ], - "main": "./dist/client/index.cjs", - "module": "./dist/client/index.js", - "types": "./dist/client/index.d.cts", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.cts", "exports": { + ".": { + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + }, + "import": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, "./client": { "require": { "types": "./dist/client/index.d.cts", diff --git a/modules/ecs/src/index.ts b/modules/ecs/src/index.ts new file mode 100644 index 00000000..637e3ef8 --- /dev/null +++ b/modules/ecs/src/index.ts @@ -0,0 +1,6 @@ +import "./shared/context-augmentation"; + +export type { Context } from "@nanoforge-dev/common"; +export type { EcsContextApi } from "./shared/ecs-context.type"; +export type { EditorComponentManifest, EditorSystemManifest } from "./shared/editor-manifest.type"; +export type { Component, Entity, Registry, SparseArray, System } from "../lib/web/libecs"; diff --git a/modules/ecs/src/shared/editor-manifest.type.ts b/modules/ecs/src/shared/editor-manifest.type.ts new file mode 100644 index 00000000..337706ad --- /dev/null +++ b/modules/ecs/src/shared/editor-manifest.type.ts @@ -0,0 +1,142 @@ +/** + * * Editor Component Element Defaults + * Basic fields for Editor Component Element + * @param Type - Type of the element + * @param Default - Type of the element's default value + */ +type ECSElementDefaults = { + /** + * Type of the element + */ + type: Type; + + /** + * Name of the element + */ + name: string; + + /** + * Description of the element + */ + description?: string; + + /** + * Example of the element + */ + example?: Default; + + /** + * Is the element optional + * @default false + */ + optional?: boolean; + + /** + * Default value of the element + * Force optional to true if set + */ + default?: Default; +}; + +/** + * * Editor Component String Element + * Type for string element + */ +type ECSStringElement = { + /** + * Values allowed for the element + */ + enum?: string[] | Record; +} & ECSElementDefaults<"string", string>; + +/** + * * Editor Component Number Element + * Type for number element + */ +type ECSNumberElement = ECSElementDefaults<"number", number>; + +/** + * * Editor Component Boolean Element + * Type for boolean element + */ +type ECSBooleanElement = ECSElementDefaults<"boolean", boolean>; + +/** + * * Editor Component Asset Element + * Type for asset element + */ +type ECSAssetElement = ECSElementDefaults<"asset", string>; + +/** + * * Editor Component Array Element + * Type for array element + */ +type ECSArrayElement = { + /** + * Items of the array + */ + items: ECSElement; +} & ECSElementDefaults<"array", any[]>; + +/** + * * Editor Component Object Element + * Type for object element + */ +type ECSObjectElement = { + /** + * Properties of the object + */ + properties: Record; +} & ECSElementDefaults<"object", object>; + +/** + * * Editor Component Element + * Type for component element + */ +type ECSElement = + | ECSStringElement + | ECSNumberElement + | ECSBooleanElement + | ECSAssetElement + | ECSArrayElement + | ECSObjectElement; + +/** + * Manifest for a component to be used in the NanoForge Editor + */ +export type EditorComponentManifest = { + /** + * Displayed name of the component + */ + name: string; + + /** + * Description of the component + */ + description?: string; + + /** + * Parameters of the component + */ + params: ECSElement[]; +}; + +/** + * Manifest for a system to be used in the NanoForge Editor + */ +export type EditorSystemManifest = { + /** + * Displayed name of the system + */ + name: string; + + /** + * Description of the system + */ + description?: string; + + /** + * Component names needed by the system + */ + dependencies: string[]; +}; diff --git a/modules/ecs/tsdown.config.ts b/modules/ecs/tsdown.config.ts index cc6d4b65..15b7d3d5 100644 --- a/modules/ecs/tsdown.config.ts +++ b/modules/ecs/tsdown.config.ts @@ -1,6 +1,7 @@ import { createTsdownConfig } from "../../tsdown.config"; export default [ + createTsdownConfig(), createTsdownConfig({ entry: "src/client/index.ts", outDir: "dist/client" }), createTsdownConfig({ entry: "src/server/index.ts", outDir: "dist/server" }), ];