@nanoforge-dev/schematics 2.2.1-beta.88f48da → 2.3.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/CHANGELOG.md +472 -0
- package/README.md +12 -15
- package/dist/collection.json +8 -23
- package/dist/index.cjs +21 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -7
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +19 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -4
- package/dist/index.js.map +1 -1
- package/dist/libs/component/component.factory.d.ts +1 -3
- package/dist/libs/component/component.factory.d.ts.map +1 -1
- package/dist/libs/component/component.factory.js +2 -1
- package/dist/libs/component/component.factory.js.map +1 -1
- package/dist/libs/project/files/js/.dockerignore +5 -0
- package/dist/libs/project/files/js/Dockerfile +36 -0
- package/dist/libs/project/files/js/README.md +53 -0
- package/dist/libs/project/files/js/assets/__dot__gitkeep +0 -0
- package/dist/libs/project/files/js/jsconfig.json +36 -0
- package/dist/libs/project/files/js/nanoforge.config.js +10 -0
- package/dist/libs/project/files/js/package.json.template +24 -0
- package/dist/libs/project/files/js/pnpm-workspace.yaml.template +3 -0
- package/dist/libs/project/files/js/src/components/drawable-circle-2d.component.js +404 -0
- package/dist/libs/project/files/js/src/components/position-2d.component.js +42 -0
- package/dist/libs/project/files/js/src/main.js +43 -0
- package/dist/libs/project/files/js/src/systems/draw-2d.system.js +33 -0
- package/dist/libs/project/files/js/src/systems/move-2d.system.js +34 -0
- package/dist/libs/project/files/js/src/systems/position-sync.system.js +35 -0
- package/dist/libs/project/files/ts/.dockerignore +5 -0
- package/dist/libs/project/files/ts/Dockerfile +36 -0
- package/dist/libs/project/files/ts/README.md +53 -0
- package/dist/libs/project/files/ts/assets/__dot__gitkeep +0 -0
- package/dist/libs/project/files/ts/nanoforge.config.ts +5 -0
- package/dist/libs/project/files/ts/package.json.template +24 -0
- package/dist/libs/project/files/ts/pnpm-workspace.yaml.template +3 -0
- package/dist/libs/project/files/ts/src/components/drawable-circle-2d.component.ts +367 -0
- package/dist/libs/project/files/ts/src/components/position-2d.component.ts +35 -0
- package/dist/libs/project/files/ts/src/main.ts +39 -0
- package/dist/libs/project/files/ts/src/systems/draw-2d.system.ts +25 -0
- package/dist/libs/project/files/ts/src/systems/move-2d.system.ts +26 -0
- package/dist/libs/project/files/ts/src/systems/position-sync.system.ts +27 -0
- package/dist/libs/project/files/ts/tsconfig.json +42 -0
- package/dist/libs/project/project.factory.d.ts +64 -0
- package/dist/libs/project/project.factory.d.ts.map +1 -0
- package/dist/libs/project/project.factory.js +122 -0
- package/dist/libs/project/project.factory.js.map +1 -0
- package/dist/libs/project/schema.json +83 -0
- package/dist/libs/system/system.factory.d.ts +1 -3
- package/dist/libs/system/system.factory.d.ts.map +1 -1
- package/dist/libs/system/system.factory.js +2 -1
- package/dist/libs/system/system.factory.js.map +1 -1
- package/dist/libs/workspace/files/js/.dockerignore +5 -0
- package/dist/libs/workspace/files/js/Dockerfile +36 -0
- package/dist/libs/workspace/files/js/README.md +51 -0
- package/dist/libs/workspace/files/js/__dot__gitignore +137 -0
- package/dist/libs/{application → workspace}/files/js/jsconfig.json +1 -2
- package/dist/libs/workspace/files/js/nanoforge.config.js +6 -0
- package/dist/libs/workspace/files/js/package.json.template +19 -0
- package/dist/libs/workspace/files/js/pnpm-workspace.yaml.template +6 -0
- package/dist/libs/workspace/files/ts/.dockerignore +5 -0
- package/dist/libs/workspace/files/ts/Dockerfile +36 -0
- package/dist/libs/workspace/files/ts/README.md +51 -0
- package/dist/libs/workspace/files/ts/__dot__gitignore +134 -0
- package/dist/libs/workspace/files/ts/nanoforge.config.ts +6 -0
- package/dist/libs/workspace/files/ts/package.json.template +20 -0
- package/dist/libs/workspace/files/ts/pnpm-workspace.yaml.template +6 -0
- package/dist/libs/{application → workspace}/files/ts/tsconfig.json +1 -2
- package/dist/libs/workspace/schema.json +45 -0
- package/dist/libs/workspace/workspace.factory.d.ts +42 -0
- package/dist/libs/workspace/workspace.factory.d.ts.map +1 -0
- package/dist/libs/workspace/workspace.factory.js +116 -0
- package/dist/libs/workspace/workspace.factory.js.map +1 -0
- package/package.json +23 -21
- package/dist/libs/application/application.factory.d.ts +0 -59
- package/dist/libs/application/application.factory.d.ts.map +0 -1
- package/dist/libs/application/application.factory.js +0 -57
- package/dist/libs/application/application.factory.js.map +0 -1
- package/dist/libs/application/files/js/.prettierignore +0 -8
- package/dist/libs/application/files/js/README.md +0 -166
- package/dist/libs/application/files/js/eslint.config.js +0 -11
- package/dist/libs/application/files/js/package.json.template +0 -48
- package/dist/libs/application/files/js/pnpm-workspace.yaml.template +0 -3
- package/dist/libs/application/files/js/prettier.config.js +0 -6
- package/dist/libs/application/files/ts/.prettierignore +0 -8
- package/dist/libs/application/files/ts/README.md +0 -166
- package/dist/libs/application/files/ts/eslint.config.js +0 -15
- package/dist/libs/application/files/ts/package.json.template +0 -52
- package/dist/libs/application/files/ts/pnpm-workspace.yaml.template +0 -3
- package/dist/libs/application/files/ts/prettier.config.js +0 -6
- package/dist/libs/application/schema.json +0 -70
- package/dist/libs/configuration/configuration.factory.d.ts +0 -31
- package/dist/libs/configuration/configuration.factory.d.ts.map +0 -1
- package/dist/libs/configuration/configuration.factory.js +0 -97
- package/dist/libs/configuration/configuration.factory.js.map +0 -1
- package/dist/libs/configuration/files/nanoforge.config.json +0 -1
- package/dist/libs/configuration/schema.json +0 -34
- package/dist/libs/docker/docker.factory.d.ts +0 -19
- package/dist/libs/docker/docker.factory.d.ts.map +0 -1
- package/dist/libs/docker/docker.factory.js +0 -20
- package/dist/libs/docker/docker.factory.js.map +0 -1
- package/dist/libs/docker/files/.dockerignore +0 -1
- package/dist/libs/docker/files/Dockerfile +0 -25
- package/dist/libs/docker/schema.json +0 -19
- package/dist/libs/part-base/files/js/__nanoforgeFolder__/client.save.json +0 -77
- package/dist/libs/part-base/files/js/__nanoforgeFolder__/server.save.json +0 -49
- package/dist/libs/part-base/files/js/__part__/components/example.component.js +0 -72
- package/dist/libs/part-base/files/js/__part__/init/after-init.js +0 -12
- package/dist/libs/part-base/files/js/__part__/init/after-registry-init.js +0 -14
- package/dist/libs/part-base/files/js/__part__/init/after-run.js +0 -12
- package/dist/libs/part-base/files/js/__part__/init/before-init.js +0 -13
- package/dist/libs/part-base/files/js/__part__/init/before-registry-init.js +0 -14
- package/dist/libs/part-base/files/js/__part__/init/before-run.js +0 -12
- package/dist/libs/part-base/files/js/__part__/systems/example.system.js +0 -44
- package/dist/libs/part-base/files/ts/__nanoforgeFolder__/client.save.json +0 -77
- package/dist/libs/part-base/files/ts/__nanoforgeFolder__/server.save.json +0 -49
- package/dist/libs/part-base/files/ts/__part__/components/example.component.ts +0 -55
- package/dist/libs/part-base/files/ts/__part__/init/after-init.ts +0 -5
- package/dist/libs/part-base/files/ts/__part__/init/after-registry-init.ts +0 -6
- package/dist/libs/part-base/files/ts/__part__/init/after-run.ts +0 -5
- package/dist/libs/part-base/files/ts/__part__/init/before-init.ts +0 -5
- package/dist/libs/part-base/files/ts/__part__/init/before-registry-init.ts +0 -6
- package/dist/libs/part-base/files/ts/__part__/init/before-run.ts +0 -5
- package/dist/libs/part-base/files/ts/__part__/systems/example.system.ts +0 -31
- package/dist/libs/part-base/part-base.factory.d.ts +0 -31
- package/dist/libs/part-base/part-base.factory.d.ts.map +0 -1
- package/dist/libs/part-base/part-base.factory.js +0 -33
- package/dist/libs/part-base/part-base.factory.js.map +0 -1
- package/dist/libs/part-base/schema.json +0 -35
- package/dist/libs/part-main/part-main.factory.d.ts +0 -39
- package/dist/libs/part-main/part-main.factory.d.ts.map +0 -1
- package/dist/libs/part-main/part-main.factory.js +0 -252
- package/dist/libs/part-main/part-main.factory.js.map +0 -1
- package/dist/libs/part-main/schema.json +0 -43
- /package/dist/libs/{application → project}/files/js/__dot__gitignore +0 -0
- /package/dist/libs/{application → project}/files/ts/__dot__gitignore +0 -0
- /package/dist/libs/{application → workspace}/files/js/__dot__env +0 -0
- /package/dist/libs/{application → workspace}/files/ts/__dot__env +0 -0
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import("@nanoforge-dev/ecs").EditorComponentManifest} EditorComponentManifest
|
|
3
|
+
* @typedef {import("@nanoforge-dev/graphics-2d").Layer} Layer
|
|
4
|
+
* @typedef {import("nanoforge").NfFile} NfFile
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Circle } from "@nanoforge-dev/graphics-2d";
|
|
8
|
+
|
|
9
|
+
export class DrawableCircle2D {
|
|
10
|
+
name = this.constructor.name;
|
|
11
|
+
shape;
|
|
12
|
+
|
|
13
|
+
/** @type {NfFile | undefined} */
|
|
14
|
+
#fillPatternImage;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {number} [radius]
|
|
18
|
+
* @param {boolean} [visible]
|
|
19
|
+
* @param {string} [id]
|
|
20
|
+
* @param {number} [opacity]
|
|
21
|
+
* @param {number} [scaleX]
|
|
22
|
+
* @param {number} [scaleY]
|
|
23
|
+
* @param {number} [skewX]
|
|
24
|
+
* @param {number} [skewY]
|
|
25
|
+
* @param {number} [rotation]
|
|
26
|
+
* @param {number} [offsetX]
|
|
27
|
+
* @param {number} [offsetY]
|
|
28
|
+
* @param {string} [fillColor]
|
|
29
|
+
* @param {NfFile} [fillPatternImage]
|
|
30
|
+
* @param {number} [fillPatternX]
|
|
31
|
+
* @param {number} [fillPatternY]
|
|
32
|
+
* @param {number} [fillPatternOffsetX]
|
|
33
|
+
* @param {number} [fillPatternOffsetY]
|
|
34
|
+
* @param {number} [fillPatternScaleX]
|
|
35
|
+
* @param {number} [fillPatternScaleY]
|
|
36
|
+
* @param {number} [fillPatternRotation]
|
|
37
|
+
* @param {string} [fillPatternRepeat]
|
|
38
|
+
*/
|
|
39
|
+
constructor(
|
|
40
|
+
radius,
|
|
41
|
+
visible,
|
|
42
|
+
id,
|
|
43
|
+
opacity,
|
|
44
|
+
scaleX,
|
|
45
|
+
scaleY,
|
|
46
|
+
skewX,
|
|
47
|
+
skewY,
|
|
48
|
+
rotation,
|
|
49
|
+
offsetX,
|
|
50
|
+
offsetY,
|
|
51
|
+
fillColor,
|
|
52
|
+
fillPatternImage,
|
|
53
|
+
fillPatternX,
|
|
54
|
+
fillPatternY,
|
|
55
|
+
fillPatternOffsetX,
|
|
56
|
+
fillPatternOffsetY,
|
|
57
|
+
fillPatternScaleX,
|
|
58
|
+
fillPatternScaleY,
|
|
59
|
+
fillPatternRotation,
|
|
60
|
+
fillPatternRepeat,
|
|
61
|
+
) {
|
|
62
|
+
this.#fillPatternImage = fillPatternImage;
|
|
63
|
+
|
|
64
|
+
this.shape = new Circle({
|
|
65
|
+
radius,
|
|
66
|
+
visible,
|
|
67
|
+
id,
|
|
68
|
+
opacity,
|
|
69
|
+
scaleX,
|
|
70
|
+
scaleY,
|
|
71
|
+
skewX,
|
|
72
|
+
skewY,
|
|
73
|
+
rotation,
|
|
74
|
+
offsetX,
|
|
75
|
+
offsetY,
|
|
76
|
+
fill: fillColor,
|
|
77
|
+
fillPatternImage: fillPatternImage
|
|
78
|
+
? Object.assign(new Image(), { src: fillPatternImage.path })
|
|
79
|
+
: undefined,
|
|
80
|
+
fillPatternX,
|
|
81
|
+
fillPatternY,
|
|
82
|
+
fillPatternOffsetX,
|
|
83
|
+
fillPatternOffsetY,
|
|
84
|
+
fillPatternScaleX,
|
|
85
|
+
fillPatternScaleY,
|
|
86
|
+
fillPatternRotation,
|
|
87
|
+
fillPatternRepeat,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
get radius() {
|
|
92
|
+
return this.shape.radius();
|
|
93
|
+
}
|
|
94
|
+
set radius(v) {
|
|
95
|
+
this.shape.radius(v);
|
|
96
|
+
this.#redraw();
|
|
97
|
+
}
|
|
98
|
+
get visible() {
|
|
99
|
+
return this.shape.visible();
|
|
100
|
+
}
|
|
101
|
+
set visible(v) {
|
|
102
|
+
this.shape.visible(v);
|
|
103
|
+
this.#redraw();
|
|
104
|
+
}
|
|
105
|
+
get id() {
|
|
106
|
+
return this.shape.id();
|
|
107
|
+
}
|
|
108
|
+
set id(v) {
|
|
109
|
+
this.shape.id(v);
|
|
110
|
+
this.#redraw();
|
|
111
|
+
}
|
|
112
|
+
get opacity() {
|
|
113
|
+
return this.shape.opacity();
|
|
114
|
+
}
|
|
115
|
+
set opacity(v) {
|
|
116
|
+
this.shape.opacity(v);
|
|
117
|
+
this.#redraw();
|
|
118
|
+
}
|
|
119
|
+
get scaleX() {
|
|
120
|
+
return this.shape.scaleX();
|
|
121
|
+
}
|
|
122
|
+
set scaleX(v) {
|
|
123
|
+
this.shape.scaleX(v);
|
|
124
|
+
this.#redraw();
|
|
125
|
+
}
|
|
126
|
+
get scaleY() {
|
|
127
|
+
return this.shape.scaleY();
|
|
128
|
+
}
|
|
129
|
+
set scaleY(v) {
|
|
130
|
+
this.shape.scaleY(v);
|
|
131
|
+
this.#redraw();
|
|
132
|
+
}
|
|
133
|
+
get skewX() {
|
|
134
|
+
return this.shape.skewX();
|
|
135
|
+
}
|
|
136
|
+
set skewX(v) {
|
|
137
|
+
this.shape.skewX(v);
|
|
138
|
+
this.#redraw();
|
|
139
|
+
}
|
|
140
|
+
get skewY() {
|
|
141
|
+
return this.shape.skewY();
|
|
142
|
+
}
|
|
143
|
+
set skewY(v) {
|
|
144
|
+
this.shape.skewY(v);
|
|
145
|
+
this.#redraw();
|
|
146
|
+
}
|
|
147
|
+
get rotation() {
|
|
148
|
+
return this.shape.rotation();
|
|
149
|
+
}
|
|
150
|
+
set rotation(v) {
|
|
151
|
+
this.shape.rotation(v);
|
|
152
|
+
this.#redraw();
|
|
153
|
+
}
|
|
154
|
+
get offsetX() {
|
|
155
|
+
return this.shape.offsetX();
|
|
156
|
+
}
|
|
157
|
+
set offsetX(v) {
|
|
158
|
+
this.shape.offsetX(v);
|
|
159
|
+
this.#redraw();
|
|
160
|
+
}
|
|
161
|
+
get offsetY() {
|
|
162
|
+
return this.shape.offsetY();
|
|
163
|
+
}
|
|
164
|
+
set offsetY(v) {
|
|
165
|
+
this.shape.offsetY(v);
|
|
166
|
+
this.#redraw();
|
|
167
|
+
}
|
|
168
|
+
get fillColor() {
|
|
169
|
+
return this.shape.fill().toString();
|
|
170
|
+
}
|
|
171
|
+
set fillColor(v) {
|
|
172
|
+
this.shape.fill(v);
|
|
173
|
+
this.#redraw();
|
|
174
|
+
}
|
|
175
|
+
/** @returns {NfFile | undefined} */
|
|
176
|
+
get fillPatternImage() {
|
|
177
|
+
return this.#fillPatternImage;
|
|
178
|
+
}
|
|
179
|
+
/** @param {NfFile} v */
|
|
180
|
+
set fillPatternImage(v) {
|
|
181
|
+
this.#fillPatternImage = v;
|
|
182
|
+
this.shape.fillPatternImage(v ? Object.assign(new Image(), { src: v.path }) : undefined);
|
|
183
|
+
this.#redraw();
|
|
184
|
+
}
|
|
185
|
+
get fillPatternX() {
|
|
186
|
+
return this.shape.fillPatternX();
|
|
187
|
+
}
|
|
188
|
+
set fillPatternX(v) {
|
|
189
|
+
this.shape.fillPatternX(v);
|
|
190
|
+
this.#redraw();
|
|
191
|
+
}
|
|
192
|
+
get fillPatternY() {
|
|
193
|
+
return this.shape.fillPatternY();
|
|
194
|
+
}
|
|
195
|
+
set fillPatternY(v) {
|
|
196
|
+
this.shape.fillPatternY(v);
|
|
197
|
+
this.#redraw();
|
|
198
|
+
}
|
|
199
|
+
get fillPatternOffsetX() {
|
|
200
|
+
return this.shape.fillPatternOffsetX();
|
|
201
|
+
}
|
|
202
|
+
set fillPatternOffsetX(v) {
|
|
203
|
+
this.shape.fillPatternOffsetX(v);
|
|
204
|
+
this.#redraw();
|
|
205
|
+
}
|
|
206
|
+
get fillPatternOffsetY() {
|
|
207
|
+
return this.shape.fillPatternOffsetY();
|
|
208
|
+
}
|
|
209
|
+
set fillPatternOffsetY(v) {
|
|
210
|
+
this.shape.fillPatternOffsetY(v);
|
|
211
|
+
this.#redraw();
|
|
212
|
+
}
|
|
213
|
+
get fillPatternScaleX() {
|
|
214
|
+
return this.shape.fillPatternScaleX();
|
|
215
|
+
}
|
|
216
|
+
set fillPatternScaleX(v) {
|
|
217
|
+
this.shape.fillPatternScaleX(v);
|
|
218
|
+
this.#redraw();
|
|
219
|
+
}
|
|
220
|
+
get fillPatternScaleY() {
|
|
221
|
+
return this.shape.fillPatternScaleY();
|
|
222
|
+
}
|
|
223
|
+
set fillPatternScaleY(v) {
|
|
224
|
+
this.shape.fillPatternScaleY(v);
|
|
225
|
+
this.#redraw();
|
|
226
|
+
}
|
|
227
|
+
get fillPatternRotation() {
|
|
228
|
+
return this.shape.fillPatternRotation();
|
|
229
|
+
}
|
|
230
|
+
set fillPatternRotation(v) {
|
|
231
|
+
this.shape.fillPatternRotation(v);
|
|
232
|
+
this.#redraw();
|
|
233
|
+
}
|
|
234
|
+
get fillPatternRepeat() {
|
|
235
|
+
return this.shape.fillPatternRepeat();
|
|
236
|
+
}
|
|
237
|
+
set fillPatternRepeat(v) {
|
|
238
|
+
this.shape.fillPatternRepeat(v);
|
|
239
|
+
this.#redraw();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** @param {Layer} layer */
|
|
243
|
+
addToLayer(layer) {
|
|
244
|
+
if (this.shape.getParent() !== layer) layer.add(this.shape);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
#redraw() {
|
|
248
|
+
this.shape.getLayer()?.batchDraw();
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// * Required to generate code
|
|
252
|
+
export default DrawableCircle2D.name;
|
|
253
|
+
|
|
254
|
+
// * Required for the editor to display the component and generate code
|
|
255
|
+
/** @type {EditorComponentManifest} */
|
|
256
|
+
export const EDITOR_COMPONENT_MANIFEST = {
|
|
257
|
+
name: "DrawableCircle2D",
|
|
258
|
+
description: "Graphically drawable circle 2D",
|
|
259
|
+
params: [
|
|
260
|
+
{
|
|
261
|
+
name: "radius",
|
|
262
|
+
type: "number",
|
|
263
|
+
description: "Radius of the circle in pixels",
|
|
264
|
+
default: 10,
|
|
265
|
+
optional: false,
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
name: "visible",
|
|
269
|
+
type: "boolean",
|
|
270
|
+
description: "Controls whether the node is rendered",
|
|
271
|
+
default: true,
|
|
272
|
+
optional: false,
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
name: "id",
|
|
276
|
+
type: "string",
|
|
277
|
+
description: "Unique identifier for the node, used with stage.findOne('#id')",
|
|
278
|
+
optional: true,
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
name: "opacity",
|
|
282
|
+
type: "number",
|
|
283
|
+
description: "Opacity from 0 (transparent) to 1 (fully opaque)",
|
|
284
|
+
default: 1,
|
|
285
|
+
optional: true,
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
name: "scaleX",
|
|
289
|
+
type: "number",
|
|
290
|
+
description: "Horizontal scale factor",
|
|
291
|
+
default: 1,
|
|
292
|
+
optional: true,
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
name: "scaleY",
|
|
296
|
+
type: "number",
|
|
297
|
+
description: "Vertical scale factor",
|
|
298
|
+
default: 1,
|
|
299
|
+
optional: true,
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
name: "skewX",
|
|
303
|
+
type: "number",
|
|
304
|
+
default: 0,
|
|
305
|
+
description: "Horizontal skew in radians, shears along the X axis",
|
|
306
|
+
optional: true,
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
name: "skewY",
|
|
310
|
+
type: "number",
|
|
311
|
+
default: 0,
|
|
312
|
+
description: "Vertical skew in radians, shears along the Y axis",
|
|
313
|
+
optional: true,
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
name: "rotation",
|
|
317
|
+
type: "number",
|
|
318
|
+
description:
|
|
319
|
+
"Rotation angle in degrees applied around the offset point (positive values rotate clockwise)",
|
|
320
|
+
default: 0,
|
|
321
|
+
optional: true,
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
name: "offsetX",
|
|
325
|
+
type: "number",
|
|
326
|
+
description: "Horizontal offset for the transform origin",
|
|
327
|
+
default: 0,
|
|
328
|
+
optional: true,
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
name: "offsetY",
|
|
332
|
+
type: "number",
|
|
333
|
+
description: "Vertical offset for the transform origin",
|
|
334
|
+
default: 0,
|
|
335
|
+
optional: true,
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
name: "fillColor",
|
|
339
|
+
type: "string",
|
|
340
|
+
description:
|
|
341
|
+
'Solid fill color as a CSS color string (e.g. "red", "#ff0000", "rgba(255,0,0,0.5)"), or a pre-built CanvasGradient object',
|
|
342
|
+
default: "red",
|
|
343
|
+
example: "rgb(255,255,255)",
|
|
344
|
+
optional: true,
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
name: "fillPatternImage",
|
|
348
|
+
type: "asset",
|
|
349
|
+
description: "Image element to use as a tiling pattern fill",
|
|
350
|
+
optional: true,
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
name: "fillPatternX",
|
|
354
|
+
type: "number",
|
|
355
|
+
description:
|
|
356
|
+
"Horizontal offset of the pattern origin relative to the shape's top-left corner, in pixels",
|
|
357
|
+
optional: true,
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
name: "fillPatternY",
|
|
361
|
+
type: "number",
|
|
362
|
+
description:
|
|
363
|
+
"Vertical offset of the pattern origin relative to the shape's top-left corner, in pixels",
|
|
364
|
+
optional: true,
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
name: "fillPatternOffsetX",
|
|
368
|
+
type: "number",
|
|
369
|
+
description: "Horizontally shifts the pattern image within the tile before repeating",
|
|
370
|
+
optional: true,
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
name: "fillPatternOffsetY",
|
|
374
|
+
type: "number",
|
|
375
|
+
description: "Vertically shifts the pattern image within the tile before repeating",
|
|
376
|
+
optional: true,
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
name: "fillPatternScaleX",
|
|
380
|
+
type: "number",
|
|
381
|
+
description: "Horizontal scale factor for the pattern tile",
|
|
382
|
+
optional: true,
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
name: "fillPatternScaleY",
|
|
386
|
+
type: "number",
|
|
387
|
+
description: "Vertical scale factor for the pattern tile",
|
|
388
|
+
optional: true,
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
name: "fillPatternRotation",
|
|
392
|
+
type: "number",
|
|
393
|
+
description: "Rotation of the pattern tile in degrees",
|
|
394
|
+
optional: true,
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
name: "fillPatternRepeat",
|
|
398
|
+
type: "string",
|
|
399
|
+
description:
|
|
400
|
+
'Repeat mode for the pattern. One of "repeat" (default), "repeat-x", "repeat-y", or "no-repeat"',
|
|
401
|
+
optional: true,
|
|
402
|
+
},
|
|
403
|
+
],
|
|
404
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import("@nanoforge-dev/ecs").EditorComponentManifest} EditorComponentManifest
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export class Position2D {
|
|
6
|
+
name = this.constructor.name;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param {number} x
|
|
10
|
+
* @param {number} y
|
|
11
|
+
*/
|
|
12
|
+
constructor(x, y) {
|
|
13
|
+
this.x = x;
|
|
14
|
+
this.y = y;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// * Required to generate code
|
|
19
|
+
export default Position2D.name;
|
|
20
|
+
|
|
21
|
+
// * Required for the editor to display the component and generate code
|
|
22
|
+
/** @type {EditorComponentManifest} */
|
|
23
|
+
export const EDITOR_COMPONENT_MANIFEST = {
|
|
24
|
+
name: "Position2D",
|
|
25
|
+
description: "Position of an entity in a 2 dimensional space in pixel",
|
|
26
|
+
params: [
|
|
27
|
+
{
|
|
28
|
+
type: "number",
|
|
29
|
+
name: "x",
|
|
30
|
+
description: "Horizontal position in pixel",
|
|
31
|
+
example: 4.2,
|
|
32
|
+
default: 0,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
type: "number",
|
|
36
|
+
name: "y",
|
|
37
|
+
description: "Vertical position in pixel",
|
|
38
|
+
example: 67,
|
|
39
|
+
default: 0,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { NanoforgeFactory } from "nanoforge";
|
|
2
|
+
import { EcsLibrary } from "@nanoforge-dev/ecs/<%= part %>";<% if (part === "client") { %>
|
|
3
|
+
import { Graphics2DLibrary } from "@nanoforge-dev/graphics-2d";
|
|
4
|
+
import { InputLibrary } from "@nanoforge-dev/input";<% } %>
|
|
5
|
+
import { <%= part === "client" ? "NetworkClientLibrary" : "NetworkServerLibrary" %> } from "@nanoforge-dev/network/<%= part %>";
|
|
6
|
+
<% if (part === "client") { %>
|
|
7
|
+
import { DrawableCircle2D } from "./components/drawable-circle-2d.component";<% } %>
|
|
8
|
+
import { Position2D } from "./components/position-2d.component";<% if (part === "client") { %>
|
|
9
|
+
import { draw2D } from "./systems/draw-2d.system";<% if (hasServer) { %>
|
|
10
|
+
import { positionSync } from "./systems/position-sync.system";<% } %><% } else { %>
|
|
11
|
+
import { move2D } from "./systems/move-2d.system";<% } %>
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {import("nanoforge").<%= part === "client" ? "ClientRunOptions" : "ServerRunOptions" %>} options
|
|
15
|
+
* @returns {Promise<void>}
|
|
16
|
+
*/
|
|
17
|
+
export const main = async (options) => {
|
|
18
|
+
const app = NanoforgeFactory.<%= part === "client" ? "createClient" : "createServer" %>({ tickRate: 60 });
|
|
19
|
+
|
|
20
|
+
const ecs = new EcsLibrary();
|
|
21
|
+
app.use(ecs);<% if (part === "client") { %>
|
|
22
|
+
app.use(new Graphics2DLibrary());
|
|
23
|
+
app.use(new InputLibrary());<% } %>
|
|
24
|
+
app.use(new <%= part === "client" ? "NetworkClientLibrary" : "NetworkServerLibrary" %>());
|
|
25
|
+
|
|
26
|
+
await app.init(options);
|
|
27
|
+
|
|
28
|
+
const registry = ecs.registry;
|
|
29
|
+
<% if (part === "client") { %>
|
|
30
|
+
const circle = registry.spawnEntity();
|
|
31
|
+
registry.addComponent(circle, new Position2D(500, 500));
|
|
32
|
+
registry.addComponent(circle, new DrawableCircle2D(75, true, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, "red"));
|
|
33
|
+
|
|
34
|
+
registry.addSystem(draw2D);<% if (hasServer) { %>
|
|
35
|
+
registry.addSystem(positionSync);<% } %>
|
|
36
|
+
<% } else { %>
|
|
37
|
+
const entity = registry.spawnEntity();
|
|
38
|
+
registry.addComponent(entity, new Position2D(500, 500));
|
|
39
|
+
|
|
40
|
+
registry.addSystem(move2D);
|
|
41
|
+
<% } %>
|
|
42
|
+
await app.run();
|
|
43
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import("@nanoforge-dev/ecs").EditorSystemManifest} EditorSystemManifest
|
|
3
|
+
* @typedef {import("@nanoforge-dev/ecs").Registry} Registry
|
|
4
|
+
* @typedef {import("nanoforge").Context} Context
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { DrawableCircle2D } from "../components/drawable-circle-2d.component";
|
|
8
|
+
import { Position2D } from "../components/position-2d.component";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {Registry} registry
|
|
12
|
+
* @param {Context} ctx
|
|
13
|
+
*/
|
|
14
|
+
export function draw2D(registry, ctx) {
|
|
15
|
+
const graphic2d = ctx.graphics;
|
|
16
|
+
|
|
17
|
+
const entities = registry.getZipper([Position2D, DrawableCircle2D]);
|
|
18
|
+
|
|
19
|
+
entities.forEach(({ Position2D, DrawableCircle2D }) => {
|
|
20
|
+
DrawableCircle2D.addToLayer(graphic2d.baseLayer);
|
|
21
|
+
DrawableCircle2D.shape.setPosition(Position2D);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
// * Required to generate code
|
|
25
|
+
export default draw2D.name;
|
|
26
|
+
|
|
27
|
+
// * Required for the editor to display the system and generate code
|
|
28
|
+
/** @type {EditorSystemManifest} */
|
|
29
|
+
export const EDITOR_SYSTEM_MANIFEST = {
|
|
30
|
+
name: "draw2D",
|
|
31
|
+
description: "Draw every drawable component",
|
|
32
|
+
dependencies: ["Position2D", "DrawableCircle2D"],
|
|
33
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import("@nanoforge-dev/ecs").EditorSystemManifest} EditorSystemManifest
|
|
3
|
+
* @typedef {import("@nanoforge-dev/ecs").Registry} Registry
|
|
4
|
+
* @typedef {import("nanoforge").Context} Context
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Position2D } from "../components/position-2d.component";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {Registry} registry
|
|
11
|
+
* @param {Context} ctx
|
|
12
|
+
*/
|
|
13
|
+
export function move2D(registry, ctx) {
|
|
14
|
+
const network = ctx.network;
|
|
15
|
+
const entities = registry.getZipper([Position2D]);
|
|
16
|
+
|
|
17
|
+
entities.forEach(({ Position2D }) => {
|
|
18
|
+
Position2D.x += 1;
|
|
19
|
+
|
|
20
|
+
network.tcp.sendToEverybody(
|
|
21
|
+
new TextEncoder().encode(JSON.stringify({ x: Position2D.x, y: Position2D.y })),
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
// * Required to generate code
|
|
26
|
+
export default move2D.name;
|
|
27
|
+
|
|
28
|
+
// * Required for the editor to display the system and generate code
|
|
29
|
+
/** @type {EditorSystemManifest} */
|
|
30
|
+
export const EDITOR_SYSTEM_MANIFEST = {
|
|
31
|
+
name: "move2D",
|
|
32
|
+
description: "Moves the entity and broadcasts its position to every connected client",
|
|
33
|
+
dependencies: ["Position2D"],
|
|
34
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import("@nanoforge-dev/ecs").EditorSystemManifest} EditorSystemManifest
|
|
3
|
+
* @typedef {import("@nanoforge-dev/ecs").Registry} Registry
|
|
4
|
+
* @typedef {import("nanoforge").Context} Context
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Position2D } from "../components/position-2d.component";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {Registry} registry
|
|
11
|
+
* @param {Context} ctx
|
|
12
|
+
*/
|
|
13
|
+
export function positionSync(registry, ctx) {
|
|
14
|
+
const network = ctx.network;
|
|
15
|
+
const packets = network.tcp
|
|
16
|
+
.getReceivedPackets()
|
|
17
|
+
.map((packet) => JSON.parse(new TextDecoder().decode(packet)));
|
|
18
|
+
|
|
19
|
+
const [entity] = registry.getZipper([Position2D]);
|
|
20
|
+
|
|
21
|
+
packets.forEach((packet) => {
|
|
22
|
+
entity.Position2D.x = packet.x;
|
|
23
|
+
entity.Position2D.y = packet.y;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
// * Required to generate code
|
|
27
|
+
export default positionSync.name;
|
|
28
|
+
|
|
29
|
+
// * Required for the editor to display the system and generate code
|
|
30
|
+
/** @type {EditorSystemManifest} */
|
|
31
|
+
export const EDITOR_SYSTEM_MANIFEST = {
|
|
32
|
+
name: "positionSync",
|
|
33
|
+
description: "Overwrites the local entity's position with the latest value received from the server",
|
|
34
|
+
dependencies: ["Position2D"],
|
|
35
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<% if (packageManager === "bun") { %>FROM oven/bun:1.3 AS base
|
|
2
|
+
<% } else if (packageManager === "pnpm") { %>FROM ghcr.io/pnpm/pnpm:12 AS base
|
|
3
|
+
RUN pnpm runtime set node 26 -g
|
|
4
|
+
<% } else { %>FROM node:26-slim AS base
|
|
5
|
+
<% } %><% if (packageManager === "yarn") { %>
|
|
6
|
+
RUN npm install -g yarn
|
|
7
|
+
<% } %>
|
|
8
|
+
WORKDIR /app
|
|
9
|
+
|
|
10
|
+
FROM base AS deps
|
|
11
|
+
|
|
12
|
+
<% if (packageManager === "npm") { %>COPY package.json package-lock.json ./
|
|
13
|
+
RUN npm ci
|
|
14
|
+
<% } else if (packageManager === "yarn") { %>COPY package.json yarn.lock ./
|
|
15
|
+
RUN yarn install --frozen-lockfile
|
|
16
|
+
<% } else if (packageManager === "pnpm") { %>COPY package.json pnpm-lock.yaml ./
|
|
17
|
+
RUN pnpm install --frozen-lockfile
|
|
18
|
+
<% } else { %>COPY package.json bun.lock ./
|
|
19
|
+
RUN bun install --frozen-lockfile
|
|
20
|
+
<% } %>
|
|
21
|
+
FROM deps AS build
|
|
22
|
+
COPY . .
|
|
23
|
+
RUN <%= packageManager %> run build
|
|
24
|
+
|
|
25
|
+
<% if (packageManager === "bun") { %>FROM oven/bun:1.3-slim<% } else { %>FROM base<% } %>
|
|
26
|
+
WORKDIR /app
|
|
27
|
+
|
|
28
|
+
COPY --from=build /app/node_modules ./node_modules
|
|
29
|
+
COPY --from=build /app/dist ./dist
|
|
30
|
+
COPY --from=build /app/package.json ./
|
|
31
|
+
COPY --from=build /app/nanoforge.config.ts ./
|
|
32
|
+
<% if (part === "server") { %>
|
|
33
|
+
<% } %><% if (packageManager !== "pnpm") { %>
|
|
34
|
+
USER <% if (packageManager === "bun") { %>bun<% } else { %>node<% } %>
|
|
35
|
+
<% } %><% if (part === "client") { %>EXPOSE 3000
|
|
36
|
+
<% } %>CMD ["<%= packageManager %>", "run", "start"]
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# <%= packageName %>
|
|
2
|
+
|
|
3
|
+
A [NanoForge](https://nanoforge.eu) <%= part %> app.
|
|
4
|
+
<% if (!workspace) { %>
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Node.js and <%= packageManager %>
|
|
8
|
+
- The [NanoForge CLI](https://www.npmjs.com/package/@nanoforge-dev/cli): `npm install -g @nanoforge-dev/cli`
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
<%= packageManager %> install
|
|
14
|
+
```
|
|
15
|
+
<% } %>
|
|
16
|
+
## Development
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
nf dev
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`nf dev` serves the game and watches your files, so changes are picked up as you work.
|
|
23
|
+
|
|
24
|
+
## Build & start
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
nf build
|
|
28
|
+
nf start
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`nf build` compiles this <%= part %> for production, and `nf start` serves the build.
|
|
32
|
+
<% if (editor) { %>
|
|
33
|
+
This app was generated with editor support. Launch it with:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
nf editor .
|
|
37
|
+
```
|
|
38
|
+
<% } %><% if (docker) { %>
|
|
39
|
+
A `Dockerfile` is also included to containerize the built app for deployment.
|
|
40
|
+
<% } %>
|
|
41
|
+
## CLI reference
|
|
42
|
+
|
|
43
|
+
| Command | Description |
|
|
44
|
+
| ------------- | ---------------------------------- |
|
|
45
|
+
| `nf dev` | Develop with hot reload |
|
|
46
|
+
| `nf build` | Build for production |
|
|
47
|
+
| `nf start` | Run a built app |<% if (editor) { %>
|
|
48
|
+
| `nf editor` | Launch the visual editor |<% } %>
|
|
49
|
+
|
|
50
|
+
## More info
|
|
51
|
+
|
|
52
|
+
- [Documentation](https://docs.nanoforge.eu) - CLI commands, configuration, and guides
|
|
53
|
+
- [nanoforge.eu](https://nanoforge.eu) - learn more about NanoForge
|
|
File without changes
|