@idosgames/module-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +28 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +118 -0
- package/dist/index.d.ts +118 -0
- package/dist/index.js +1 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 iDos Games
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# @idosgames/module-sdk
|
|
2
|
+
|
|
3
|
+
The composable-module **contract** for the iDosGames host shell. A module is a self-contained
|
|
4
|
+
feature — a game (Three/Phaser), a plain app, or an AI app — that plugs into the host: it declares a
|
|
5
|
+
`Module` manifest and, in `setup(ctx)`, registers what it contributes (a rendered `EngineScene`,
|
|
6
|
+
React `UiPanel`s, a nav route). Framework-neutral at runtime — React and `@idosgames/core` are
|
|
7
|
+
referenced as types only, so a renderer-less module pulls in neither.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { defineModule } from "@idosgames/module-sdk";
|
|
11
|
+
|
|
12
|
+
export const myModule = defineModule({
|
|
13
|
+
id: "my-game",
|
|
14
|
+
meta: { name: "My Game", type: "game", genre: "arcade", engine: "three" },
|
|
15
|
+
setup(ctx) {
|
|
16
|
+
ctx.registerScene(scene); // mount/activate/suspend/destroy
|
|
17
|
+
ctx.registerPanel(panel); // React UI in a host slot
|
|
18
|
+
ctx.registerRoute({ id: "my-game", label: "Play", icon: "🎮" });
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Key types: `Module`, `ModuleContext`, `EngineScene`, `SceneMountContext`, `UiPanel`, `SurfaceAllocator`,
|
|
24
|
+
`RouteEntry`, `SharedEventBus`. The host runtime is [`@idosgames/app-shell`](https://www.npmjs.com/package/@idosgames/app-shell);
|
|
25
|
+
shared React glue is [`@idosgames/react`](https://www.npmjs.com/package/@idosgames/react).
|
|
26
|
+
|
|
27
|
+
See the full design in `docs/composable-modules-architecture.md`, or load the `idosgames-module-contract`
|
|
28
|
+
skill (via the `@idosgames/mcp` server).
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';function t(e){return e}exports.defineModule=t;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { IDosGamesClient } from '@idosgames/core';
|
|
2
|
+
export { IDosGamesClient, SdkEvents } from '@idosgames/core';
|
|
3
|
+
import { ComponentType } from 'react';
|
|
4
|
+
|
|
5
|
+
/** What a module is, for catalog/UI purposes. Not every module is a game. */
|
|
6
|
+
type ModuleType = "game" | "app" | "ai-app";
|
|
7
|
+
/**
|
|
8
|
+
* Rendering family a module needs a surface for. `"dom"` means no GPU renderer — a pure
|
|
9
|
+
* React/DOM module (an app or AI app). The host mode-switches between different engines and may,
|
|
10
|
+
* later, compose modules of the same engine family.
|
|
11
|
+
*/
|
|
12
|
+
type ModuleEngine = "three" | "phaser" | "dom";
|
|
13
|
+
interface ModuleMeta {
|
|
14
|
+
/** Human-readable name shown in the catalog and nav. */
|
|
15
|
+
name: string;
|
|
16
|
+
type: ModuleType;
|
|
17
|
+
/** Genre tag for games ("board", "idle-rpg", "sandbox", …). Optional for non-games. */
|
|
18
|
+
genre?: string;
|
|
19
|
+
engine: ModuleEngine;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The manifest a module exports. The host calls `setup` exactly once, passing shared services;
|
|
23
|
+
* the module registers its scene/panels/routes and returns nothing.
|
|
24
|
+
*/
|
|
25
|
+
interface Module {
|
|
26
|
+
/** Stable unique id — also the mode id the nav switches by. */
|
|
27
|
+
id: string;
|
|
28
|
+
meta: ModuleMeta;
|
|
29
|
+
setup(ctx: ModuleContext): void;
|
|
30
|
+
}
|
|
31
|
+
/** Services the host injects into every module at `setup` time. */
|
|
32
|
+
interface ModuleContext {
|
|
33
|
+
/** The one shared, already-authenticated SDK client. Modules never create their own. */
|
|
34
|
+
client: IDosGamesClient;
|
|
35
|
+
/** Cross-module bus — e.g. an idle module emits "gold:granted", a board module reacts. */
|
|
36
|
+
events: SharedEventBus;
|
|
37
|
+
/** Requests host-managed DOM surfaces (canvas hosts, HUD slots) when a module needs one directly. */
|
|
38
|
+
surface: SurfaceAllocator;
|
|
39
|
+
/** Register a rendered scene (Three/Phaser/custom). The host drives its lifecycle. */
|
|
40
|
+
registerScene(scene: EngineScene): void;
|
|
41
|
+
/** Register a React UI panel placed into one of the host's slots. */
|
|
42
|
+
registerPanel(panel: UiPanel): void;
|
|
43
|
+
/** Register a nav / mode entry so the player can switch to this module. */
|
|
44
|
+
registerRoute(entry: RouteEntry): void;
|
|
45
|
+
}
|
|
46
|
+
/** Where on screen a surface lives. The host's layout decides actual placement. */
|
|
47
|
+
type SurfaceKind = "fullbleed-canvas" | "sidebar-panel" | "overlay" | "hud-slot";
|
|
48
|
+
interface SurfaceHandle {
|
|
49
|
+
/** The DOM element the module renders into. */
|
|
50
|
+
readonly host: HTMLElement;
|
|
51
|
+
/** Release the surface and remove the element (module teardown). */
|
|
52
|
+
release(): void;
|
|
53
|
+
}
|
|
54
|
+
/** Hands out host-managed DOM surfaces for modules that mount into the DOM directly. */
|
|
55
|
+
interface SurfaceAllocator {
|
|
56
|
+
request(kind: SurfaceKind): SurfaceHandle;
|
|
57
|
+
}
|
|
58
|
+
/** Passed to `EngineScene.mount`. An object (not a bare element) so it can grow — e.g. a
|
|
59
|
+
* host-shared renderer in the composition era — without breaking the contract. */
|
|
60
|
+
interface SceneMountContext {
|
|
61
|
+
/** The element this scene attaches its canvas/DOM to. */
|
|
62
|
+
host: HTMLElement;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* A rendered scene the host drives. In the Mode Router model the scene owns its renderer but MUST
|
|
66
|
+
* stop its RAF loop on `suspend` and resume on `activate` — only one engine is visible at a time.
|
|
67
|
+
*/
|
|
68
|
+
interface EngineScene {
|
|
69
|
+
/** Preferred host surface. Defaults to `"fullbleed-canvas"` when omitted. */
|
|
70
|
+
readonly surface?: SurfaceKind;
|
|
71
|
+
/** Create the renderer and attach to the host element. Called once. */
|
|
72
|
+
mount(ctx: SceneMountContext): void;
|
|
73
|
+
/** This scene became the active mode — resume RAF / re-acquire input. */
|
|
74
|
+
activate?(): void;
|
|
75
|
+
/** This scene was hidden — pause RAF / release input. Not destroyed; may re-activate. */
|
|
76
|
+
suspend?(): void;
|
|
77
|
+
/** Optional per-frame tick if the module opts into the host's shared loop. */
|
|
78
|
+
update?(deltaMs: number): void;
|
|
79
|
+
/** Permanent teardown — dispose GPU resources, remove listeners. */
|
|
80
|
+
destroy(): void;
|
|
81
|
+
}
|
|
82
|
+
/** Named region of the host layout a panel renders into. */
|
|
83
|
+
type PanelSlot = "hud" | "sidebar" | "overlay" | "modal";
|
|
84
|
+
interface UiPanel {
|
|
85
|
+
/** Unique within the module. */
|
|
86
|
+
id: string;
|
|
87
|
+
slot: PanelSlot;
|
|
88
|
+
/** React component rendered by the host inside the shared provider stack. Takes no props —
|
|
89
|
+
* it reads shared state through the host's hooks (`useIDosGamesClient`, etc.). */
|
|
90
|
+
component: ComponentType;
|
|
91
|
+
/** Render only while this module's mode is active. Defaults to `true`. A shared HUD that must
|
|
92
|
+
* stay visible across modes sets this `false`. */
|
|
93
|
+
activeOnly?: boolean;
|
|
94
|
+
/** Sort order within the slot; lower renders first. */
|
|
95
|
+
order?: number;
|
|
96
|
+
}
|
|
97
|
+
/** A nav / mode entry contributed to the host's mode router. */
|
|
98
|
+
interface RouteEntry {
|
|
99
|
+
/** Mode id — conventionally the owning module's `id`. The host switches modes by this. */
|
|
100
|
+
id: string;
|
|
101
|
+
label: string;
|
|
102
|
+
/** Optional icon (emoji or short glyph the host nav renders). */
|
|
103
|
+
icon?: string;
|
|
104
|
+
order?: number;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Typed pub/sub shared by every module. Defaults to an open `Record<string, unknown>` topic map;
|
|
108
|
+
* a host may parameterize it with a known event map for stronger typing.
|
|
109
|
+
*/
|
|
110
|
+
interface SharedEventBus<Events extends Record<string, unknown> = Record<string, unknown>> {
|
|
111
|
+
emit<K extends keyof Events & string>(topic: K, payload: Events[K]): void;
|
|
112
|
+
/** Subscribe; returns an unsubscribe function. */
|
|
113
|
+
on<K extends keyof Events & string>(topic: K, handler: (payload: Events[K]) => void): () => void;
|
|
114
|
+
}
|
|
115
|
+
/** Identity helper that pins a module literal to the `Module` type for editor help and errors. */
|
|
116
|
+
declare function defineModule(module: Module): Module;
|
|
117
|
+
|
|
118
|
+
export { type EngineScene, type Module, type ModuleContext, type ModuleEngine, type ModuleMeta, type ModuleType, type PanelSlot, type RouteEntry, type SceneMountContext, type SharedEventBus, type SurfaceAllocator, type SurfaceHandle, type SurfaceKind, type UiPanel, defineModule };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { IDosGamesClient } from '@idosgames/core';
|
|
2
|
+
export { IDosGamesClient, SdkEvents } from '@idosgames/core';
|
|
3
|
+
import { ComponentType } from 'react';
|
|
4
|
+
|
|
5
|
+
/** What a module is, for catalog/UI purposes. Not every module is a game. */
|
|
6
|
+
type ModuleType = "game" | "app" | "ai-app";
|
|
7
|
+
/**
|
|
8
|
+
* Rendering family a module needs a surface for. `"dom"` means no GPU renderer — a pure
|
|
9
|
+
* React/DOM module (an app or AI app). The host mode-switches between different engines and may,
|
|
10
|
+
* later, compose modules of the same engine family.
|
|
11
|
+
*/
|
|
12
|
+
type ModuleEngine = "three" | "phaser" | "dom";
|
|
13
|
+
interface ModuleMeta {
|
|
14
|
+
/** Human-readable name shown in the catalog and nav. */
|
|
15
|
+
name: string;
|
|
16
|
+
type: ModuleType;
|
|
17
|
+
/** Genre tag for games ("board", "idle-rpg", "sandbox", …). Optional for non-games. */
|
|
18
|
+
genre?: string;
|
|
19
|
+
engine: ModuleEngine;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The manifest a module exports. The host calls `setup` exactly once, passing shared services;
|
|
23
|
+
* the module registers its scene/panels/routes and returns nothing.
|
|
24
|
+
*/
|
|
25
|
+
interface Module {
|
|
26
|
+
/** Stable unique id — also the mode id the nav switches by. */
|
|
27
|
+
id: string;
|
|
28
|
+
meta: ModuleMeta;
|
|
29
|
+
setup(ctx: ModuleContext): void;
|
|
30
|
+
}
|
|
31
|
+
/** Services the host injects into every module at `setup` time. */
|
|
32
|
+
interface ModuleContext {
|
|
33
|
+
/** The one shared, already-authenticated SDK client. Modules never create their own. */
|
|
34
|
+
client: IDosGamesClient;
|
|
35
|
+
/** Cross-module bus — e.g. an idle module emits "gold:granted", a board module reacts. */
|
|
36
|
+
events: SharedEventBus;
|
|
37
|
+
/** Requests host-managed DOM surfaces (canvas hosts, HUD slots) when a module needs one directly. */
|
|
38
|
+
surface: SurfaceAllocator;
|
|
39
|
+
/** Register a rendered scene (Three/Phaser/custom). The host drives its lifecycle. */
|
|
40
|
+
registerScene(scene: EngineScene): void;
|
|
41
|
+
/** Register a React UI panel placed into one of the host's slots. */
|
|
42
|
+
registerPanel(panel: UiPanel): void;
|
|
43
|
+
/** Register a nav / mode entry so the player can switch to this module. */
|
|
44
|
+
registerRoute(entry: RouteEntry): void;
|
|
45
|
+
}
|
|
46
|
+
/** Where on screen a surface lives. The host's layout decides actual placement. */
|
|
47
|
+
type SurfaceKind = "fullbleed-canvas" | "sidebar-panel" | "overlay" | "hud-slot";
|
|
48
|
+
interface SurfaceHandle {
|
|
49
|
+
/** The DOM element the module renders into. */
|
|
50
|
+
readonly host: HTMLElement;
|
|
51
|
+
/** Release the surface and remove the element (module teardown). */
|
|
52
|
+
release(): void;
|
|
53
|
+
}
|
|
54
|
+
/** Hands out host-managed DOM surfaces for modules that mount into the DOM directly. */
|
|
55
|
+
interface SurfaceAllocator {
|
|
56
|
+
request(kind: SurfaceKind): SurfaceHandle;
|
|
57
|
+
}
|
|
58
|
+
/** Passed to `EngineScene.mount`. An object (not a bare element) so it can grow — e.g. a
|
|
59
|
+
* host-shared renderer in the composition era — without breaking the contract. */
|
|
60
|
+
interface SceneMountContext {
|
|
61
|
+
/** The element this scene attaches its canvas/DOM to. */
|
|
62
|
+
host: HTMLElement;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* A rendered scene the host drives. In the Mode Router model the scene owns its renderer but MUST
|
|
66
|
+
* stop its RAF loop on `suspend` and resume on `activate` — only one engine is visible at a time.
|
|
67
|
+
*/
|
|
68
|
+
interface EngineScene {
|
|
69
|
+
/** Preferred host surface. Defaults to `"fullbleed-canvas"` when omitted. */
|
|
70
|
+
readonly surface?: SurfaceKind;
|
|
71
|
+
/** Create the renderer and attach to the host element. Called once. */
|
|
72
|
+
mount(ctx: SceneMountContext): void;
|
|
73
|
+
/** This scene became the active mode — resume RAF / re-acquire input. */
|
|
74
|
+
activate?(): void;
|
|
75
|
+
/** This scene was hidden — pause RAF / release input. Not destroyed; may re-activate. */
|
|
76
|
+
suspend?(): void;
|
|
77
|
+
/** Optional per-frame tick if the module opts into the host's shared loop. */
|
|
78
|
+
update?(deltaMs: number): void;
|
|
79
|
+
/** Permanent teardown — dispose GPU resources, remove listeners. */
|
|
80
|
+
destroy(): void;
|
|
81
|
+
}
|
|
82
|
+
/** Named region of the host layout a panel renders into. */
|
|
83
|
+
type PanelSlot = "hud" | "sidebar" | "overlay" | "modal";
|
|
84
|
+
interface UiPanel {
|
|
85
|
+
/** Unique within the module. */
|
|
86
|
+
id: string;
|
|
87
|
+
slot: PanelSlot;
|
|
88
|
+
/** React component rendered by the host inside the shared provider stack. Takes no props —
|
|
89
|
+
* it reads shared state through the host's hooks (`useIDosGamesClient`, etc.). */
|
|
90
|
+
component: ComponentType;
|
|
91
|
+
/** Render only while this module's mode is active. Defaults to `true`. A shared HUD that must
|
|
92
|
+
* stay visible across modes sets this `false`. */
|
|
93
|
+
activeOnly?: boolean;
|
|
94
|
+
/** Sort order within the slot; lower renders first. */
|
|
95
|
+
order?: number;
|
|
96
|
+
}
|
|
97
|
+
/** A nav / mode entry contributed to the host's mode router. */
|
|
98
|
+
interface RouteEntry {
|
|
99
|
+
/** Mode id — conventionally the owning module's `id`. The host switches modes by this. */
|
|
100
|
+
id: string;
|
|
101
|
+
label: string;
|
|
102
|
+
/** Optional icon (emoji or short glyph the host nav renders). */
|
|
103
|
+
icon?: string;
|
|
104
|
+
order?: number;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Typed pub/sub shared by every module. Defaults to an open `Record<string, unknown>` topic map;
|
|
108
|
+
* a host may parameterize it with a known event map for stronger typing.
|
|
109
|
+
*/
|
|
110
|
+
interface SharedEventBus<Events extends Record<string, unknown> = Record<string, unknown>> {
|
|
111
|
+
emit<K extends keyof Events & string>(topic: K, payload: Events[K]): void;
|
|
112
|
+
/** Subscribe; returns an unsubscribe function. */
|
|
113
|
+
on<K extends keyof Events & string>(topic: K, handler: (payload: Events[K]) => void): () => void;
|
|
114
|
+
}
|
|
115
|
+
/** Identity helper that pins a module literal to the `Module` type for editor help and errors. */
|
|
116
|
+
declare function defineModule(module: Module): Module;
|
|
117
|
+
|
|
118
|
+
export { type EngineScene, type Module, type ModuleContext, type ModuleEngine, type ModuleMeta, type ModuleType, type PanelSlot, type RouteEntry, type SceneMountContext, type SharedEventBus, type SurfaceAllocator, type SurfaceHandle, type SurfaceKind, type UiPanel, defineModule };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function t(e){return e}export{t as defineModule};
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@idosgames/module-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The composable-module contract for the iDosGames host shell: Module / ModuleContext types plus tiny authoring helpers. Framework-neutral at runtime — a module can be a game (Three/Phaser), a plain app, or an AI app.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "iDos Games",
|
|
8
|
+
"homepage": "https://github.com/iDos-Games/iDosGamesSDK_TS#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/iDos-Games/iDosGamesSDK_TS.git",
|
|
12
|
+
"directory": "packages/module-sdk"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/iDos-Games/iDosGamesSDK_TS/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"idosgames",
|
|
19
|
+
"sdk",
|
|
20
|
+
"module",
|
|
21
|
+
"plugin",
|
|
22
|
+
"gamedev"
|
|
23
|
+
],
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"sideEffects": false,
|
|
28
|
+
"main": "./dist/index.cjs",
|
|
29
|
+
"module": "./dist/index.js",
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"import": "./dist/index.js",
|
|
35
|
+
"require": "./dist/index.cjs"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"README.md",
|
|
41
|
+
"LICENSE"
|
|
42
|
+
],
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsup",
|
|
45
|
+
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
46
|
+
},
|
|
47
|
+
"//": "@idosgames/core is a real range, not '*': a published contract must name the version of core whose IDosGamesClient/SdkEvents shapes it references. Bump in step with core (see RELEASING.md). react is an OPTIONAL peer — the contract references React's ComponentType type only (a UI panel is a React component), which is erased at build, so a runtime-only module needs no React.",
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@idosgames/core": "^0.1.1"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"react": "^18.3.1 || ^19.0.0"
|
|
53
|
+
},
|
|
54
|
+
"peerDependenciesMeta": {
|
|
55
|
+
"react": {
|
|
56
|
+
"optional": true
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@types/react": "^19.2.17",
|
|
61
|
+
"react": "^19.2.7"
|
|
62
|
+
}
|
|
63
|
+
}
|