canvasengine 1.3.0 → 2.0.1-beta.1

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.
Files changed (125) hide show
  1. package/.cursorrules +0 -0
  2. package/.github/workflows/ci.yml +29 -0
  3. package/README.md +79 -0
  4. package/dist/compiler/vite.js +119 -0
  5. package/dist/compiler/vite.js.map +1 -0
  6. package/dist/index.d.ts +846 -0
  7. package/dist/index.js +3340 -0
  8. package/dist/index.js.map +1 -0
  9. package/index.d.ts +6 -0
  10. package/logo.png +0 -0
  11. package/package.json +84 -18
  12. package/src/compiler/grammar.pegjs +180 -0
  13. package/src/compiler/vite.ts +166 -0
  14. package/src/components/Canvas.ts +134 -0
  15. package/src/components/Container.ts +46 -0
  16. package/src/components/DisplayObject.ts +458 -0
  17. package/src/components/DrawMap/index.ts +65 -0
  18. package/src/components/Graphic.ts +147 -0
  19. package/src/components/NineSliceSprite.ts +46 -0
  20. package/src/components/ParticleEmitter.ts +39 -0
  21. package/src/components/Scene.ts +6 -0
  22. package/src/components/Sprite.ts +493 -0
  23. package/src/components/Text.ts +145 -0
  24. package/src/components/Tilemap/Tile.ts +79 -0
  25. package/src/components/Tilemap/TileGroup.ts +207 -0
  26. package/src/components/Tilemap/TileLayer.ts +163 -0
  27. package/src/components/Tilemap/TileSet.ts +41 -0
  28. package/src/components/Tilemap/index.ts +80 -0
  29. package/src/components/TilingSprite.ts +39 -0
  30. package/src/components/Viewport.ts +159 -0
  31. package/src/components/index.ts +12 -0
  32. package/src/components/types/DisplayObject.ts +68 -0
  33. package/src/components/types/MouseEvent.ts +3 -0
  34. package/src/components/types/Spritesheet.ts +389 -0
  35. package/src/components/types/index.ts +4 -0
  36. package/src/directives/Drag.ts +84 -0
  37. package/src/directives/KeyboardControls.ts +922 -0
  38. package/src/directives/Scheduler.ts +112 -0
  39. package/src/directives/Sound.ts +91 -0
  40. package/src/directives/Transition.ts +45 -0
  41. package/src/directives/ViewportCull.ts +40 -0
  42. package/src/directives/ViewportFollow.ts +26 -0
  43. package/src/directives/index.ts +7 -0
  44. package/src/engine/animation.ts +113 -0
  45. package/src/engine/bootstrap.ts +19 -0
  46. package/src/engine/directive.ts +23 -0
  47. package/src/engine/reactive.ts +379 -0
  48. package/src/engine/signal.ts +138 -0
  49. package/src/engine/trigger.ts +40 -0
  50. package/src/engine/utils.ts +135 -0
  51. package/src/hooks/addContext.ts +6 -0
  52. package/src/hooks/useProps.ts +155 -0
  53. package/src/hooks/useRef.ts +21 -0
  54. package/src/index.ts +14 -0
  55. package/src/presets/Bar.ts +89 -0
  56. package/src/presets/Button.ts +0 -0
  57. package/src/presets/Joystick.ts +286 -0
  58. package/src/presets/NightAmbiant.ts +122 -0
  59. package/src/presets/Particle.ts +53 -0
  60. package/src/utils/Ease.ts +33 -0
  61. package/src/utils/RadialGradient.ts +86 -0
  62. package/starter/assets/logo.png +0 -0
  63. package/starter/components/app.ce +18 -0
  64. package/starter/components/hello.ce +35 -0
  65. package/starter/index.html +21 -0
  66. package/starter/main.ts +6 -0
  67. package/starter/package.json +20 -0
  68. package/starter/tsconfig.json +32 -0
  69. package/starter/vite.config.ts +12 -0
  70. package/tsconfig.json +32 -0
  71. package/tsconfig.node.json +10 -0
  72. package/tsup.config.ts +28 -0
  73. package/vitest.config.ts +12 -0
  74. package/.gitattributes +0 -22
  75. package/.npmignore +0 -163
  76. package/canvasengine-1.3.0.all.min.js +0 -21
  77. package/canvasengine.js +0 -5802
  78. package/core/DB.js +0 -24
  79. package/core/ModelServer.js +0 -348
  80. package/core/Users.js +0 -190
  81. package/core/engine-common.js +0 -952
  82. package/doc/cocoonjs.md +0 -36
  83. package/doc/doc-lang.yml +0 -43
  84. package/doc/doc-router.yml +0 -14
  85. package/doc/doc-tuto.yml +0 -9
  86. package/doc/doc.yml +0 -39
  87. package/doc/element.md +0 -37
  88. package/doc/entity.md +0 -90
  89. package/doc/extend.md +0 -47
  90. package/doc/get_started.md +0 -19
  91. package/doc/images/entity.png +0 -0
  92. package/doc/multitouch.md +0 -58
  93. package/doc/nodejs.md +0 -142
  94. package/doc/scene.md +0 -44
  95. package/doc/text.md +0 -156
  96. package/examples/server/client.html +0 -31
  97. package/examples/server/server.js +0 -16
  98. package/examples/tiled_server/client.html +0 -52
  99. package/examples/tiled_server/images/tiles_spritesheet.png +0 -0
  100. package/examples/tiled_server/server/map.json +0 -50
  101. package/examples/tiled_server/server/map.tmx +0 -16
  102. package/examples/tiled_server/server/server.js +0 -16
  103. package/extends/Animation.js +0 -910
  104. package/extends/Effect.js +0 -252
  105. package/extends/Gleed2d.js +0 -252
  106. package/extends/Hit.js +0 -1509
  107. package/extends/Input.js +0 -699
  108. package/extends/Marshal.js +0 -716
  109. package/extends/Scrolling.js +0 -388
  110. package/extends/Soundmanager2.js +0 -5466
  111. package/extends/Spritesheet.js +0 -196
  112. package/extends/Text.js +0 -366
  113. package/extends/Tiled.js +0 -403
  114. package/extends/Window.js +0 -575
  115. package/extends/gamepad.js +0 -397
  116. package/extends/socket.io.min.js +0 -2
  117. package/extends/swf/soundmanager2.swf +0 -0
  118. package/extends/swf/soundmanager2_debug.swf +0 -0
  119. package/extends/swf/soundmanager2_flash9.swf +0 -0
  120. package/extends/swf/soundmanager2_flash9_debug.swf +0 -0
  121. package/extends/swf/soundmanager2_flash_xdomain.zip +0 -0
  122. package/extends/workers/transition.js +0 -43
  123. package/index.js +0 -46
  124. package/license.txt +0 -19
  125. package/readme.md +0 -483
@@ -0,0 +1,458 @@
1
+ import { Node } from "yoga-layout";
2
+ import { Element, isElement, Props } from "../engine/reactive";
3
+ import { setObservablePoint } from "../engine/utils";
4
+ import type {
5
+ AlignContent,
6
+ EdgeSize,
7
+ FlexDirection,
8
+ Size,
9
+ } from "./types/DisplayObject";
10
+ import { effect, Signal, signal } from "@signe/reactive";
11
+ import { DropShadowFilter } from "pixi-filters";
12
+ import { BlurFilter, ObservablePoint } from "pixi.js";
13
+
14
+ export interface ComponentInstance extends PixiMixins.ContainerOptions {
15
+ id?: string;
16
+ children?: ComponentInstance[];
17
+ onInit?(props: Props): void;
18
+ onUpdate?(props: Props): void;
19
+ onDestroy?(parent: Element): void;
20
+ onMount?(context: Element, index?: number): void;
21
+ setWidth(width: number): void;
22
+ setHeight(height: number): void;
23
+ }
24
+
25
+ export const EVENTS = [
26
+ "added",
27
+ "childAdded",
28
+ "childRemoved",
29
+ "click",
30
+ "clickcapture",
31
+ "destroyed",
32
+ "globalmousemove",
33
+ "globalpointermove",
34
+ "globaltouchmove",
35
+ "mousedown",
36
+ "mousedowncapture",
37
+ "mouseenter",
38
+ "mouseentercapture",
39
+ "mouseleave",
40
+ "mouseleavecapture",
41
+ "mousemove",
42
+ "mousemovecapture",
43
+ "mouseout",
44
+ "mouseoutcapture",
45
+ "mouseover",
46
+ "mouseovercapture",
47
+ "mouseup",
48
+ "mouseupcapture",
49
+ "mouseupoutside",
50
+ "mouseupoutsidecapture",
51
+ "pointercancel",
52
+ "pointercancelcapture",
53
+ "pointerdown",
54
+ "pointerdowncapture",
55
+ "pointerenter",
56
+ "pointerentercapture",
57
+ "pointerleave",
58
+ "pointerleavecapture",
59
+ "pointermove",
60
+ "pointermovecapture",
61
+ "pointerout",
62
+ "pointeroutcapture",
63
+ "pointerover",
64
+ "pointerovercapture",
65
+ "pointertap",
66
+ "pointertapcapture",
67
+ "pointerup",
68
+ "pointerupcapture",
69
+ "pointerupoutside",
70
+ "pointerupoutsidecapture",
71
+ "removed",
72
+ "rightclick",
73
+ "rightclickcapture",
74
+ "rightdown",
75
+ "rightdowncapture",
76
+ "rightup",
77
+ "rightupcapture",
78
+ "rightupoutside",
79
+ "rightupoutsidecapture",
80
+ "tap",
81
+ "tapcapture",
82
+ "touchcancel",
83
+ "touchcancelcapture",
84
+ "touchend",
85
+ "touchendcapture",
86
+ "touchendoutside",
87
+ "touchendoutsidecapture",
88
+ "touchmove",
89
+ "touchmovecapture",
90
+ "touchstart",
91
+ "touchstartcapture",
92
+ "wheel",
93
+ "wheelcapture",
94
+ ];
95
+
96
+ export function DisplayObject(extendClass) {
97
+ return class DisplayObject extends extendClass {
98
+ #canvasContext: {
99
+ [key: string]: any;
100
+ } | null = null;
101
+ isFlex: boolean = false;
102
+ fullProps: Props = {};
103
+ isMounted: boolean = false;
104
+ _anchorPoints = new ObservablePoint(
105
+ { _onUpdate: () => {} },
106
+ 0,
107
+ 0
108
+ );
109
+ isCustomAnchor: boolean = false;
110
+ displayWidth = signal(0);
111
+ displayHeight = signal(0);
112
+ overrideProps: string[] = [];
113
+ node: Node;
114
+
115
+ get yoga() {
116
+ return this.#canvasContext?.Yoga;
117
+ }
118
+
119
+ get deltaRatio() {
120
+ return this.#canvasContext?.scheduler?.tick.value.deltaRatio;
121
+ }
122
+
123
+ onInit(props) {
124
+ this._id = props.id;
125
+ for (let event of EVENTS) {
126
+ if (props[event] && !this.overrideProps.includes(event)) {
127
+ this.eventMode = "static";
128
+ this.on(event, props[event]);
129
+ }
130
+ }
131
+ }
132
+
133
+ onMount({ parent, props }: Element<DisplayObject>, index?: number) {
134
+ this.#canvasContext = props.context;
135
+ this.node = this.yoga.Node.create();
136
+ if (parent) {
137
+ const instance = parent.componentInstance as DisplayObject;
138
+ if (index === undefined) {
139
+ instance.addChild(this);
140
+ } else {
141
+ instance.addChildAt(this, index);
142
+ }
143
+ if (instance.layer) this.parentLayer = instance.layer;
144
+ this.isMounted = true;
145
+ this.effectSize(props.width, props.height);
146
+ this.onUpdate(props);
147
+ this.parent.node.insertChild(
148
+ this.node,
149
+ this.parent.node.getChildCount()
150
+ );
151
+ if (parent.props.flexDirection) {
152
+ this.parent.node.calculateLayout();
153
+ for (let child of this.parent.children) {
154
+ const { left, top } = child.getComputedLayout();
155
+ child.x = left;
156
+ child.y = top;
157
+ }
158
+ }
159
+
160
+ }
161
+ }
162
+
163
+ effectSize(width: Size, height: Size) {
164
+ const handleSize = (
165
+ size: Size,
166
+ setter: (value: number) => void,
167
+ parentSize: Signal<number>
168
+ ) => {
169
+ if (typeof size === "string" && size.endsWith("%")) {
170
+ effect(() => {
171
+ setter(parentSize() * (parseInt(size) / 100));
172
+ if (this.isFlex) {
173
+ this.#applyFlexLayout();
174
+ }
175
+ });
176
+ } else {
177
+ setter(+size);
178
+ }
179
+ };
180
+
181
+ if (width != undefined)
182
+ handleSize(width, this.setWidth.bind(this), this.parent.displayWidth);
183
+ if (height != undefined)
184
+ handleSize(
185
+ height,
186
+ this.setHeight.bind(this),
187
+ this.parent.displayHeight
188
+ );
189
+ }
190
+
191
+ #applyFlexLayout() {
192
+ this.calculateLayout();
193
+ for (let child of this.children) {
194
+ const { left, top } = child.node.getComputedLayout();
195
+ child.x = left;
196
+ child.y = top;
197
+ }
198
+ }
199
+
200
+ #flexRender(props) {
201
+ if (!this.parent) return;
202
+ if (props.flexDirection || props.justifyContent) {
203
+ this.isFlex = true;
204
+ this.#applyFlexLayout();
205
+ }
206
+ }
207
+
208
+ onUpdate(props) {
209
+ this.fullProps = {
210
+ ...this.fullProps,
211
+ ...props,
212
+ };
213
+
214
+ if (!this.#canvasContext || !this.parent) return;
215
+ if (props.x !== undefined) this.setX(props.x);
216
+ if (props.y !== undefined) this.setY(props.y);
217
+ if (props.scale !== undefined)
218
+ setObservablePoint(this.scale, props.scale);
219
+ if (props.anchor !== undefined && !this.isCustomAnchor) {
220
+ setObservablePoint(this.anchor, props.anchor);
221
+ }
222
+ if (props.skew !== undefined) setObservablePoint(this.skew, props.skew);
223
+ if (props.tint) this.tint = props.tint;
224
+ if (props.rotation !== undefined) this.rotation = props.rotation;
225
+ if (props.angle !== undefined) this.angle = props.angle;
226
+ if (props.zIndex !== undefined) this.zIndex = props.zIndex;
227
+ if (props.roundPixels !== undefined) this.roundPixels = props.roundPixels;
228
+ if (props.cursor) this.cursor = props.cursor;
229
+ if (props.visible !== undefined) this.visible = props.visible;
230
+ if (props.alpha !== undefined) this.alpha = props.alpha;
231
+ if (props.pivot) setObservablePoint(this.pivot, props.pivot);
232
+ if (props.flexDirection) this.setFlexDirection(props.flexDirection);
233
+ if (props.flexWrap) this.setFlexWrap(props.flexWrap);
234
+ if (props.justifyContent) this.setJustifyContent(props.justifyContent);
235
+ if (props.alignItems) this.setAlignItems(props.alignItems);
236
+ if (props.alignContent) this.setAlignContent(props.alignContent);
237
+ if (props.alignSelf) this.setAlignSelf(props.alignSelf);
238
+ if (props.margin) this.setMargin(props.margin);
239
+ if (props.padding) this.setPadding(props.padding);
240
+ if (props.gap) this.setGap(props.gap);
241
+ if (props.border) this.setBorder(props.border);
242
+ if (props.positionType) this.setPositionType(props.positionType);
243
+ if (props.filters) this.filters = props.filters;
244
+ if (props.maskOf) {
245
+ if (isElement(props.maskOf)) {
246
+ props.maskOf.componentInstance.mask = this;
247
+ }
248
+ }
249
+ if (props.blendMode) this.blendMode = props.blendMode;
250
+ if (props.filterArea) this.filterArea = props.filterArea;
251
+ const currentFilters = this.filters || [];
252
+
253
+ if (props.shadow) {
254
+ let dropShadowFilter = currentFilters.find(
255
+ (filter) => filter instanceof DropShadowFilter
256
+ );
257
+ if (!dropShadowFilter) {
258
+ dropShadowFilter = new DropShadowFilter();
259
+ currentFilters.push(dropShadowFilter);
260
+ }
261
+ Object.assign(dropShadowFilter, props.shadow);
262
+ }
263
+
264
+ if (props.blur) {
265
+ let blurFilter = currentFilters.find(
266
+ (filter) => filter instanceof BlurFilter
267
+ );
268
+ if (!blurFilter) {
269
+ const options =
270
+ typeof props.blur === "number"
271
+ ? {
272
+ strength: props.blur,
273
+ }
274
+ : props.blur;
275
+ blurFilter = new BlurFilter(options);
276
+ currentFilters.push(blurFilter);
277
+ }
278
+ Object.assign(blurFilter, props.blur);
279
+ }
280
+
281
+ this.filters = currentFilters;
282
+
283
+ this.#flexRender(props);
284
+ }
285
+
286
+ onDestroy() {
287
+ super.destroy();
288
+ this.node?.freeRecursive();
289
+ }
290
+
291
+ getComputedLayout() {
292
+ return this.node.getComputedLayout();
293
+ }
294
+
295
+ applyComputedLayout() {
296
+ const layout = this.getComputedLayout();
297
+ this.x = layout.left;
298
+ this.y = layout.top;
299
+ }
300
+
301
+ calculateLayout() {
302
+ this.node.calculateLayout();
303
+ }
304
+
305
+ setFlexDirection(direction: FlexDirection) {
306
+ const mapping = {
307
+ row: this.yoga.FLEX_DIRECTION_ROW,
308
+ column: this.yoga.FLEX_DIRECTION_COLUMN,
309
+ "row-reverse": this.yoga.FLEX_DIRECTION_ROW_REVERSE,
310
+ "column-reverse": this.yoga.FLEX_DIRECTION_COLUMN_REVERSE,
311
+ };
312
+ this.node.setFlexDirection(mapping[direction]);
313
+ }
314
+
315
+ setFlexWrap(wrap: "wrap" | "nowrap" | "wrap-reverse") {
316
+ const mapping = {
317
+ wrap: this.yoga.WRAP_WRAP,
318
+ nowrap: this.yoga.WRAP_NO_WRAP,
319
+ "wrap-reverse": this.yoga.WRAP_WRAP_REVERSE,
320
+ };
321
+ this.node.setFlexWrap(mapping[wrap]);
322
+ }
323
+
324
+ #setAlign(methodName: string, align: AlignContent) {
325
+ const mapping = {
326
+ auto: this.yoga.ALIGN_AUTO,
327
+ "flex-start": this.yoga.ALIGN_FLEX_START,
328
+ "flex-end": this.yoga.ALIGN_FLEX_END,
329
+ center: this.yoga.ALIGN_CENTER,
330
+ stretch: this.yoga.ALIGN_STRETCH,
331
+ baseline: this.yoga.ALIGN_BASELINE,
332
+ "space-between": this.yoga.ALIGN_SPACE_BETWEEN,
333
+ "space-around": this.yoga.ALIGN_SPACE_AROUND,
334
+ };
335
+ const method = (this.node as any)[methodName].bind(this.node);
336
+ method(mapping[align]);
337
+ }
338
+
339
+ setAlignContent(align: AlignContent) {
340
+ this.#setAlign("setAlignContent", align);
341
+ }
342
+
343
+ setAlignSelf(align: AlignContent) {
344
+ this.#setAlign("setAlignSelf", align);
345
+ }
346
+
347
+ setAlignItems(align: AlignContent) {
348
+ this.#setAlign("setAlignItems", align);
349
+ }
350
+
351
+ setJustifyContent(
352
+ justifyContent:
353
+ | "flex-start"
354
+ | "flex-end"
355
+ | "center"
356
+ | "space-between"
357
+ | "space-around"
358
+ ) {
359
+ const mapping = {
360
+ "flex-start": this.yoga.JUSTIFY_FLEX_START,
361
+ "flex-end": this.yoga.JUSTIFY_FLEX_END,
362
+ center: this.yoga.JUSTIFY_CENTER,
363
+ "space-between": this.yoga.JUSTIFY_SPACE_BETWEEN,
364
+ "space-around": this.yoga.JUSTIFY_SPACE_AROUND,
365
+ };
366
+ this.node.setJustifyContent(mapping[justifyContent]);
367
+ }
368
+
369
+ #setEdgeSize(methodName: string, size: EdgeSize) {
370
+ const method = (this.node as any)[methodName].bind(this.node);
371
+ if (size instanceof Array) {
372
+ if (size.length === 2) {
373
+ method(this.yoga.EDGE_VERTICAL, size[0]);
374
+ method(this.yoga.EDGE_HORIZONTAL, size[1]);
375
+ } else if (size.length === 4) {
376
+ method(this.yoga.EDGE_TOP, size[0]);
377
+ method(this.yoga.EDGE_RIGHT, size[1]);
378
+ method(this.yoga.EDGE_BOTTOM, size[2]);
379
+ method(this.yoga.EDGE_LEFT, size[3]);
380
+ }
381
+ } else {
382
+ method(this.yoga.EDGE_ALL, size);
383
+ }
384
+ }
385
+
386
+ setPosition(position: EdgeSize) {
387
+ this.#setEdgeSize("setPosition", position);
388
+ }
389
+
390
+ setX(x: number) {
391
+ x = x + this.getWidth() * this._anchorPoints.x;
392
+ if (!this.parent.isFlex) {
393
+ this.x = x;
394
+ }
395
+ this.node.setPosition(this.yoga.EDGE_LEFT, x);
396
+ }
397
+
398
+ setY(y: number) {
399
+ y = y + this.getHeight() * this._anchorPoints.y;
400
+ if (!this.parent.isFlex) {
401
+ this.y = y;
402
+ }
403
+ this.node.setPosition(this.yoga.EDGE_TOP, y);
404
+ }
405
+
406
+ setPadding(padding: EdgeSize) {
407
+ this.#setEdgeSize("setPadding", padding);
408
+ }
409
+
410
+ setMargin(margin: EdgeSize) {
411
+ this.#setEdgeSize("setMargin", margin);
412
+ }
413
+
414
+ setGap(gap: EdgeSize) {
415
+ this.node.setGap(this.yoga.GAP_ALL, +gap);
416
+ }
417
+
418
+ setBorder(border: EdgeSize) {
419
+ this.#setEdgeSize("setBorder", border);
420
+ }
421
+
422
+ setPositionType(positionType: "relative" | "absolute") {
423
+ const mapping = {
424
+ relative: this.yoga.POSITION_TYPE_RELATIVE,
425
+ absolute: this.yoga.POSITION_TYPE_ABSOLUTE,
426
+ };
427
+ this.node.setPositionType(mapping[positionType]);
428
+ }
429
+
430
+ calculateBounds() {
431
+ super.calculateBounds();
432
+ if (!this._geometry) return;
433
+ const bounds = this._geometry.bounds;
434
+ const width = Math.abs(bounds.minX - bounds.maxX);
435
+ const height = Math.abs(bounds.minY - bounds.maxY);
436
+ // this.node.setWidth(width);
437
+ // this.node.setHeight(height);
438
+ }
439
+
440
+ setWidth(width: number) {
441
+ this.displayWidth.set(width);
442
+ this.node?.setWidth(width);
443
+ }
444
+
445
+ setHeight(height: number) {
446
+ this.displayHeight.set(height);
447
+ this.node?.setHeight(height);
448
+ }
449
+
450
+ getWidth() {
451
+ return this.displayWidth();
452
+ }
453
+
454
+ getHeight() {
455
+ return this.displayHeight();
456
+ }
457
+ };
458
+ }
@@ -0,0 +1,65 @@
1
+ import { effect, signal } from "@signe/reactive";
2
+ import { loop } from "../../engine/reactive";
3
+ import { h } from "../../engine/signal";
4
+ import { useProps } from "../../hooks/useProps";
5
+ import { Container } from "../Container";
6
+ import { Sprite } from "../Sprite";
7
+
8
+ interface TileData {
9
+ id: number;
10
+ rect: [number, number, number, number];
11
+ drawIn: [number, number];
12
+ layerIndex: number;
13
+ }
14
+
15
+ export function ImageMap(props) {
16
+ const { imageSource, tileData } = useProps(props);
17
+ const tiles = signal<TileData[]>([]);
18
+
19
+ effect(async () => {
20
+ const data = await fetch(tileData()).then((response) => response.json());
21
+ const objects = data;
22
+ if (props.objects) {
23
+ objects.push(...props.objects(data));
24
+ }
25
+ tiles.set(objects);
26
+ });
27
+
28
+ const createLayeredTiles = () => {
29
+ const layers = [createTileLayer(0), createTileLayer(1, true), createTileLayer(2)];
30
+
31
+ return h(Container, props, ...layers);
32
+ };
33
+
34
+ const createTileLayer = (layerIndex: number, sortableChildren = false) => {
35
+ return h(
36
+ Container,
37
+ {
38
+ sortableChildren,
39
+ },
40
+ loop(tiles, (object) => {
41
+
42
+ if (object.tag && layerIndex == 1) {
43
+ return object
44
+ }
45
+
46
+ object.layerIndex ||= 1;
47
+ if (object.layerIndex !== layerIndex) return null;
48
+
49
+ const [x, y, width, height] = object.rect;
50
+ const [drawX, drawY] = object.drawIn;
51
+
52
+ return h(Sprite, {
53
+ image: imageSource(),
54
+ x: drawX,
55
+ y: drawY,
56
+ rectangle: { x, y, width, height },
57
+ zIndex: drawY + height - 70,
58
+ // zIndex: 0
59
+ });
60
+ })
61
+ );
62
+ };
63
+
64
+ return createLayeredTiles();
65
+ }
@@ -0,0 +1,147 @@
1
+ import { effect, Signal } from "@signe/reactive";
2
+ import { Graphics as PixiGraphics } from "pixi.js";
3
+ import { createComponent, registerComponent } from "../engine/reactive";
4
+ import { DisplayObject } from "./DisplayObject";
5
+ import { DisplayObjectProps } from "./types/DisplayObject";
6
+ import { useProps } from "../hooks/useProps";
7
+
8
+ interface GraphicsProps extends DisplayObjectProps {
9
+ draw?: (graphics: PixiGraphics) => void;
10
+ }
11
+
12
+ interface RectProps extends DisplayObjectProps {
13
+ width: number;
14
+ height: number;
15
+ color: string;
16
+ }
17
+
18
+ interface CircleProps extends DisplayObjectProps {
19
+ radius: number;
20
+ color: string;
21
+ }
22
+
23
+ interface EllipseProps extends DisplayObjectProps {
24
+ width: number;
25
+ height: number;
26
+ color: string;
27
+ }
28
+
29
+ interface TriangleProps extends DisplayObjectProps {
30
+ base: number;
31
+ height: number;
32
+ color: string;
33
+ }
34
+
35
+ interface SvgProps extends DisplayObjectProps {
36
+ svg: string;
37
+ }
38
+
39
+ class CanvasGraphics extends DisplayObject(PixiGraphics) {
40
+ onInit(props: GraphicsProps) {
41
+ super.onInit(props);
42
+ if (props.draw) {
43
+ effect(() => {
44
+ this.clear();
45
+ props.draw?.(this);
46
+ });
47
+ }
48
+ }
49
+ }
50
+
51
+ interface CanvasGraphics extends PixiGraphics {}
52
+
53
+ registerComponent("Graphics", CanvasGraphics);
54
+
55
+ export function Graphics(props: GraphicsProps) {
56
+ return createComponent("Graphics", props);
57
+ }
58
+
59
+ export function Rect(props: RectProps) {
60
+ const { width, height, color, borderRadius, border } = useProps(props, {
61
+ borderRadius: null,
62
+ border: null
63
+ })
64
+ return Graphics({
65
+ draw: (g) => {
66
+ if (borderRadius()) {
67
+ g.roundRect(0, 0, width(), height(), borderRadius());
68
+ } else {
69
+ g.rect(0, 0, width(), height());
70
+ }
71
+ if (border) {
72
+ g.stroke(border);
73
+ }
74
+ g.fill(color());
75
+ },
76
+ ...props
77
+ })
78
+ }
79
+
80
+ function drawShape(g: PixiGraphics, shape: 'circle' | 'ellipse', props: {
81
+ radius: Signal<number>;
82
+ color: Signal<string>;
83
+ border: Signal<number>;
84
+ } | {
85
+ width: Signal<number>;
86
+ height: Signal<number>;
87
+ color: Signal<string>;
88
+ border: Signal<number>;
89
+ }) {
90
+ const { color, border } = props;
91
+ if ('radius' in props) {
92
+ g.circle(0, 0, props.radius());
93
+ } else {
94
+ g.ellipse(0, 0, props.width() / 2, props.height() / 2);
95
+ }
96
+ if (border()) {
97
+ g.stroke(border());
98
+ }
99
+ g.fill(color());
100
+ }
101
+
102
+ export function Circle(props: CircleProps) {
103
+ const { radius, color, border } = useProps(props, {
104
+ border: null
105
+ })
106
+ return Graphics({
107
+ draw: (g) => drawShape(g, 'circle', { radius, color, border }),
108
+ ...props
109
+ })
110
+ }
111
+
112
+ export function Ellipse(props: EllipseProps) {
113
+ const { width, height, color, border } = useProps(props, {
114
+ border: null
115
+ })
116
+ return Graphics({
117
+ draw: (g) => drawShape(g, 'ellipse', { width, height, color, border }),
118
+ ...props
119
+ })
120
+ }
121
+
122
+ export function Triangle(props: TriangleProps) {
123
+ const { width, height, color, border } = useProps(props, {
124
+ border: null,
125
+ color: '#000'
126
+ })
127
+ return Graphics({
128
+ draw: (g) => {
129
+ g.moveTo(0, height());
130
+ g.lineTo(width() / 2, 0);
131
+ g.lineTo(width(), height());
132
+ g.lineTo(0, height());
133
+ g.fill(color());
134
+ if (border) {
135
+ g.stroke(border);
136
+ }
137
+ },
138
+ ...props
139
+ })
140
+ }
141
+
142
+ export function Svg(props: SvgProps) {
143
+ return Graphics({
144
+ draw: (g) => g.svg(props.svg),
145
+ ...props
146
+ })
147
+ }
@@ -0,0 +1,46 @@
1
+ import { Assets, NineSliceSprite as PixiNineSliceSprite, Texture } from "pixi.js";
2
+ import { createComponent, registerComponent } from "../engine/reactive";
3
+ import { DisplayObject } from "./DisplayObject";
4
+ import { DisplayObjectProps } from "./types/DisplayObject";
5
+
6
+ interface NineSliceSpriteProps extends DisplayObjectProps {
7
+ image?: string;
8
+ texture?: Texture;
9
+ width?: number;
10
+ height?: number;
11
+ leftWidth?: number;
12
+ rightWidth?: number;
13
+ topHeight?: number;
14
+ bottomHeight?: number;
15
+ roundPixels?: boolean;
16
+ }
17
+
18
+ class CanvasNineSliceSprite extends DisplayObject(PixiNineSliceSprite) {
19
+ constructor() {
20
+ // @ts-ignore
21
+ super({
22
+ width: 0,
23
+ height: 0
24
+ });
25
+ }
26
+
27
+ async onUpdate(props: NineSliceSpriteProps) {
28
+ for (const [key, value] of Object.entries(props)) {
29
+ if (value !== undefined) {
30
+ if (key === 'image') {
31
+ this.texture = await Assets.load(value);
32
+ } else if (key in this) {
33
+ (this as any)[key] = value;
34
+ }
35
+ }
36
+ }
37
+ }
38
+ }
39
+
40
+ interface CanvasNineSliceSprite extends PixiNineSliceSprite {}
41
+
42
+ registerComponent("NineSliceSprite", CanvasNineSliceSprite);
43
+
44
+ export function NineSliceSprite(props: NineSliceSpriteProps) {
45
+ return createComponent("NineSliceSprite", props);
46
+ }