@canvasengine/presets 2.0.0-beta.2 → 2.0.0-beta.21

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.
@@ -0,0 +1,146 @@
1
+ import {
2
+ CompositeTilemap,
3
+ POINT_STRUCT_SIZE,
4
+ Tilemap,
5
+ settings,
6
+ } from "@canvasengine/tilemap";
7
+ import { Layer, Tile as TileClass } from "@rpgjs/tiled";
8
+ import {
9
+ createComponent,
10
+ registerComponent,
11
+ DisplayObject,
12
+ Signal,
13
+ } from "canvasengine";
14
+ import { Tile } from "./Tile";
15
+ import { TileSet } from "./TileSet";
16
+ import { Subscription } from "rxjs";
17
+
18
+ settings.use32bitIndex = true;
19
+
20
+ export class CanvasTileLayer extends DisplayObject(CompositeTilemap) {
21
+ private _tiles: any = {};
22
+ tiles: (TileClass | null)[];
23
+ private _layer: any; // TODO: fix this, remove any. replace with Layer
24
+ private frameTile: number = 0;
25
+ private frameRateAnimation: number = 10;
26
+ private subscriptionTick: Subscription;
27
+
28
+ static findTileSet(gid: number, tileSets: TileSet[]) {
29
+ let tileset: TileSet | undefined;
30
+ for (let i = tileSets.length - 1; i >= 0; i--) {
31
+ tileset = tileSets[i];
32
+ if (tileset.firstgid && tileset.firstgid <= gid) {
33
+ break;
34
+ }
35
+ }
36
+ return tileset;
37
+ }
38
+
39
+ /** @internal */
40
+ createTile(x: number, y: number, options: any = {}): Tile | undefined {
41
+ const { real, filter } = options;
42
+ const { tilewidth, tileheight, width } = this._layer;
43
+ if (real) {
44
+ x = Math.floor(x / tilewidth);
45
+ y = Math.floor(y / tileheight);
46
+ }
47
+ const i = x + y * width;
48
+ const tiledTile = this._layer.getTileByIndex(i);
49
+
50
+ if (!tiledTile || (tiledTile && tiledTile.gid == 0)) return;
51
+
52
+ const tileset = CanvasTileLayer.findTileSet(tiledTile.gid, this.tileSets);
53
+
54
+ if (!tileset) return;
55
+
56
+ const tile = new Tile(tiledTile, tileset);
57
+
58
+ tile.x = x * tilewidth;
59
+ tile.y = y * tileheight + (tileheight - tile.texture.height);
60
+
61
+ tile._x = x;
62
+ tile._y = y;
63
+
64
+ if (tileset.tileoffset) {
65
+ tile.x += tileset.tileoffset.x ?? 0;
66
+ tile.y += tileset.tileoffset.y ?? 0;
67
+ }
68
+
69
+ if (filter) {
70
+ const ret = filter(tile);
71
+ if (!ret) return;
72
+ }
73
+
74
+ return tile;
75
+ }
76
+
77
+ private _addFrame(tile: Tile, x: number, y: number) {
78
+ const frame = this.tile(tile.texture, tile.x, tile.y, {
79
+ rotate: tile.texture.rotate,
80
+ });
81
+ // const pb = this.pointsBuf
82
+ // if (!pb) return null
83
+ // tile.pointsBufIndex = pb.length - POINT_STRUCT_SIZE
84
+ tile.setAnimation(frame);
85
+ this._tiles[x + ";" + y] = tile;
86
+ }
87
+
88
+ async onMount(args) {
89
+ const { props } = args;
90
+
91
+ this.tileSets = props.tilesets;
92
+ this._layer = new Layer(
93
+ {
94
+ ...props,
95
+ },
96
+ this.tileSets
97
+ );
98
+
99
+ const tick: Signal = props.context.tick;
100
+
101
+ this.subscriptionTick = tick.observable.subscribe(({ value }) => {
102
+ if (value.frame % this.frameRateAnimation == 0) {
103
+ this.tileAnim = [this.frameTile, this.frameTile];
104
+ this.frameTile++
105
+ }
106
+ });
107
+
108
+ super.onMount(args);
109
+ }
110
+
111
+ onUpdate(props) {
112
+ super.onUpdate(props);
113
+ if (!this.isMounted) return;
114
+ if (props.tileheight) this._layer.tileheight = props.tileheight;
115
+ if (props.tilewidth) this._layer.tilewidth = props.tilewidth;
116
+ if (props.width) this._layer.width = props.width;
117
+ if (props.height) this._layer.height = props.height;
118
+ if (props.parallaxX) this._layer.parallaxX = props.parallaxx;
119
+ if (props.parallaxY) this._layer.parallaxY = props.parallaxy;
120
+
121
+ this.removeChildren();
122
+
123
+ for (let y = 0; y < this._layer.height; y++) {
124
+ for (let x = 0; x < this._layer.width; x++) {
125
+ const tile = this.createTile(x, y);
126
+ if (tile) {
127
+ this._addFrame(tile, x, y);
128
+ }
129
+ }
130
+ }
131
+ }
132
+
133
+ async onDestroy(parent: any) {
134
+ this.subscriptionTick.unsubscribe();
135
+ await super.onDestroy(parent);
136
+ }
137
+ }
138
+
139
+ // @ts-ignore
140
+ export interface CanvasTileLayer extends CompositeTilemap {}
141
+
142
+ registerComponent("CompositeTileLayer", CanvasTileLayer);
143
+
144
+ export function CompositeTileLayer(props) {
145
+ return createComponent("CompositeTileLayer", props);
146
+ }
@@ -0,0 +1,41 @@
1
+ import { TiledTileset, Tileset as TiledTilesetClass } from "@rpgjs/tiled";
2
+ import { Assets, Rectangle, Texture } from "pixi.js";
3
+
4
+ export class TileSet extends TiledTilesetClass {
5
+ public textures: Texture[] = [];
6
+ private tileGroups = {};
7
+
8
+ constructor(tileSet: TiledTileset) {
9
+ super(tileSet);
10
+ }
11
+
12
+ loadGroup() {
13
+ // for (let tile of this.tileset.tiles) {
14
+ // }
15
+ }
16
+
17
+ /** @internal */
18
+ async load(image: string) {
19
+ const texture = await Assets.load(image);
20
+ for (
21
+ let y = this.margin;
22
+ y < this.image.height;
23
+ y += this.tileheight + this.spacing
24
+ ) {
25
+ for (
26
+ let x = this.margin;
27
+ x < this.image.width;
28
+ x += this.tilewidth + this.spacing
29
+ ) {
30
+ this.textures.push(
31
+ new Texture({
32
+ source: texture.source,
33
+ frame: new Rectangle(+x, +y, +this.tilewidth, +this.tileheight),
34
+ })
35
+ );
36
+ }
37
+ }
38
+ this.loadGroup();
39
+ return this;
40
+ }
41
+ }
@@ -0,0 +1,222 @@
1
+ import { TiledLayer, TiledLayerType, TiledMap, TiledParserFile, TiledTileset } from "@rpgjs/tiled"
2
+ import { loop, h, Container, TilingSprite, useProps, effect, signal } from "canvasengine"
3
+ import { CompositeTileLayer } from "./TileLayer"
4
+ import { TileSet } from "./TileSet"
5
+
6
+ /**
7
+ * Reorganizes tile layers based on the z property of tiles
8
+ *
9
+ * This function analyzes each tile in the layer data and groups them by their z property.
10
+ * If a tile has a z property different from 0, it creates new layers for each z value.
11
+ *
12
+ * @param {TiledLayer[]} originalLayers - The original layers from the tilemap
13
+ * @param {TileSet[]} tilesets - Array of loaded tilesets
14
+ * @param {TiledMap} mapData - The complete map data
15
+ * @returns {TiledLayer[]} - Reorganized layers with tiles grouped by z property
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const reorganizedLayers = reorganizeLayersByTileZ(mapData.layers, tilesets, mapData);
20
+ * ```
21
+ */
22
+ function reorganizeLayersByTileZ(originalLayers: TiledLayer[], tilesets: TileSet[], mapData: TiledMap): TiledLayer[] {
23
+ const reorganizedLayers: TiledLayer[] = [];
24
+
25
+ for (const layer of originalLayers) {
26
+ if (layer.type !== TiledLayerType.Tile) {
27
+ // Keep non-tile layers as they are
28
+ reorganizedLayers.push(layer);
29
+ continue;
30
+ }
31
+
32
+ // Group tiles by their z property
33
+ const layersByZ = new Map<number, number[]>();
34
+
35
+ // Initialize empty arrays for all z values we'll find
36
+ // Don't pre-populate with original data anymore
37
+
38
+ // Ensure layer data is number array
39
+ let layerData: number[];
40
+ if (Array.isArray(layer.data)) {
41
+ layerData = layer.data.map(gid => {
42
+ if (typeof gid === 'number') {
43
+ return gid;
44
+ } else {
45
+ return parseInt(String(gid), 10);
46
+ }
47
+ });
48
+ } else {
49
+ // If data is a string, it might be compressed - for now, skip this layer
50
+ reorganizedLayers.push(layer);
51
+ continue;
52
+ }
53
+
54
+ let tilesProcessed = 0;
55
+ let tilesWithZ = 0;
56
+
57
+ // Analyze each tile in the layer
58
+ for (let i = 0; i < layerData.length; i++) {
59
+ const gid = layerData[i];
60
+
61
+ if (gid === 0) continue; // Empty tile
62
+
63
+ tilesProcessed++;
64
+
65
+ // Find the corresponding tileset
66
+ let tileset: TileSet | undefined;
67
+ for (let j = tilesets.length - 1; j >= 0; j--) {
68
+ if (tilesets[j].firstgid && tilesets[j].firstgid <= gid) {
69
+ tileset = tilesets[j];
70
+ break;
71
+ }
72
+ }
73
+
74
+ if (!tileset) {
75
+ // If no tileset found, put tile in z=0 layer
76
+ if (!layersByZ.has(0)) {
77
+ layersByZ.set(0, new Array(layerData.length).fill(0));
78
+ }
79
+ layersByZ.get(0)![i] = gid;
80
+ continue;
81
+ }
82
+
83
+ // Get tile properties from tileset
84
+ const localTileId = gid - tileset.firstgid;
85
+ // @ts-ignore
86
+ const tileProperties = tileset.tileset.tiles?.[localTileId]?.properties;
87
+ const zValue = tileProperties?.z ?? 0;
88
+
89
+ // Count tiles with explicit z property
90
+ if (tileProperties?.z !== undefined) {
91
+ tilesWithZ++;
92
+ }
93
+
94
+ // Create or get the layer for this z value
95
+ if (!layersByZ.has(zValue)) {
96
+ layersByZ.set(zValue, new Array(layerData.length).fill(0));
97
+ }
98
+
99
+ // Place tile in the appropriate z layer
100
+ layersByZ.get(zValue)![i] = gid;
101
+ }
102
+
103
+ // Create layers for each z value, ensuring z=0 comes first
104
+ const sortedZValues = Array.from(layersByZ.keys()).sort((a, b) => a - b);
105
+
106
+ for (const zValue of sortedZValues) {
107
+ const layerDataForZ = layersByZ.get(zValue)!;
108
+
109
+ // Only create layer if it has tiles
110
+ if (layerDataForZ.some(gid => gid !== 0)) {
111
+ const newLayer = {
112
+ ...layer,
113
+ name: `${layer.name}_z${zValue}`, // Always add _z suffix
114
+ data: layerDataForZ,
115
+ properties: {
116
+ ...layer.properties,
117
+ z: zValue
118
+ }
119
+ };
120
+
121
+ reorganizedLayers.push(newLayer);
122
+ }
123
+ }
124
+ }
125
+
126
+ // Sort final layers to ensure z=0 layers come first, then by z value
127
+ reorganizedLayers.sort((a, b) => {
128
+ const zA = a.properties?.z ?? 0.5;
129
+ const zB = b.properties?.z ?? 0.5;
130
+ return zA - zB;
131
+ });
132
+
133
+ return reorganizedLayers;
134
+ }
135
+
136
+ export function TiledMap(props) {
137
+ const { map, basePath, createLayersPerTilesZ } = useProps(props, {
138
+ createLayersPerTilesZ: false,
139
+ basePath: ''
140
+ })
141
+ const layers = signal<TiledLayer[]>([])
142
+ const objectLayer = props.objectLayer
143
+ let tilesets: TileSet[] = []
144
+ let mapData: TiledMap = {} as TiledMap
145
+
146
+ const parseTmx = async (file: string, relativePath: string = '') => {
147
+ if (typeof file !== 'string') {
148
+ return file
149
+ }
150
+ // @ts-ignore
151
+ const parser = new TiledParserFile(
152
+ file,
153
+ {
154
+ basePath: '',
155
+ staticDir: '',
156
+ relativePath
157
+ }
158
+ )
159
+ const data = await parser.parseFilePromise({
160
+ getOnlyBasename: false
161
+ })
162
+
163
+ return data
164
+ }
165
+
166
+ effect(async () => {
167
+ const _map = map()
168
+ if (_map) {
169
+ mapData = await parseTmx(_map, basePath())
170
+ tilesets = [] // Reset tilesets array
171
+ for (let tileSet of mapData.tilesets) {
172
+ // @ts-ignore
173
+ if (tileSet.tile) tileSet.tiles = tileSet.tile
174
+ if (!tileSet.tiles) tileSet.tiles = []
175
+ tilesets.push(await new TileSet(tileSet).load(tileSet.image.source))
176
+ }
177
+
178
+ // Reorganize layers by tile z property if enabled
179
+ let finalLayers = mapData.layers;
180
+ if (createLayersPerTilesZ()) {
181
+ finalLayers = reorganizeLayersByTileZ(mapData.layers, tilesets, mapData);
182
+ }
183
+
184
+ layers.set(finalLayers)
185
+ }
186
+ })
187
+
188
+ const createLayer = (layers, props = {}) => {
189
+ return h(Container, props, loop<any>(layers, (layer) => {
190
+ switch (layer.type) {
191
+ case TiledLayerType.Tile:
192
+ return h(CompositeTileLayer, {
193
+ tilewidth: mapData.tilewidth,
194
+ tileheight: mapData.tileheight,
195
+ // @ts-ignore
196
+ width: mapData.width,
197
+ // @ts-ignore
198
+ height: mapData.height,
199
+ ...layer,
200
+ tilesets
201
+ })
202
+ case TiledLayerType.Image:
203
+ const { width, height, source } = layer.image
204
+ return h(TilingSprite, {
205
+ image: source,
206
+ ...layer,
207
+ width: layer.repeatx ? layer.width * layer.tilewidth : width,
208
+ height: layer.repeaty ? layer.height * layer.tileheight : height
209
+ })
210
+ case TiledLayerType.Group:
211
+ return createLayer(signal(layer.layers), layer)
212
+ case TiledLayerType.ObjectGroup:
213
+ const child = objectLayer?.(layer)
214
+ return h(Container, layer, child)
215
+ default:
216
+ return h(Container)
217
+ }
218
+ }))
219
+ }
220
+
221
+ return h(Container, props, createLayer(layers))
222
+ }
@@ -0,0 +1,224 @@
1
+ import {
2
+ tick,
3
+ useProps,
4
+ h,
5
+ Mesh,
6
+ signal,
7
+ } from "canvasengine";
8
+ import { Geometry, Shader, GlProgram, UniformGroup } from "pixi.js";
9
+
10
+ /**
11
+ * Weather Effect Component
12
+ *
13
+ * Creates a realistic rain effect using WebGL shaders with customizable parameters.
14
+ * The effect simulates raindrops falling with wind influence, density control, and speed adjustment.
15
+ *
16
+ * ## Design
17
+ *
18
+ * The component uses a fragment shader to generate procedural rain drops with:
19
+ * - **Procedural generation**: Each raindrop is generated using hash functions for randomness
20
+ * - **Wind simulation**: Raindrops are affected by wind direction and strength as they fall
21
+ * - **Density control**: Number of visible raindrops can be adjusted
22
+ * - **Speed variation**: Each drop has slightly different falling speed for realism
23
+ * - **Visual styling**: Zelda-inspired rain appearance with proper fade effects
24
+ *
25
+ * @param {Object} options - Configuration options for the weather effect
26
+ * @param {number} [options.speed=0.5] - Rain falling speed (0.1 = slow, 2.0 = fast)
27
+ * @param {number} [options.windDirection=0.0] - Wind direction (-1.0 = left, 1.0 = right)
28
+ * @param {number} [options.windStrength=0.2] - Wind strength (0.0 = no wind, 1.0 = strong)
29
+ * @param {number} [options.density=180.0] - Rain density (number of raindrops, 50-400)
30
+ * @param {Array<number>} [options.resolution=[1000, 1000]] - Screen resolution for proper scaling
31
+ *
32
+ * @example
33
+ * ```jsx
34
+ * // Basic usage with default settings
35
+ * <Weather />
36
+ *
37
+ * // Customized heavy rain with strong wind
38
+ * <Weather
39
+ * speed={1.5}
40
+ * windDirection={0.8}
41
+ * windStrength={0.6}
42
+ * density={300}
43
+ * />
44
+ *
45
+ * // Light drizzle
46
+ * <Weather
47
+ * speed={0.2}
48
+ * density={80}
49
+ * windStrength={0.1}
50
+ * />
51
+ *
52
+ * // Using signals for dynamic control
53
+ * const rainSpeed = signal(0.5);
54
+ * const windDir = signal(0.0);
55
+ *
56
+ * <Weather
57
+ * speed={rainSpeed}
58
+ * windDirection={windDir}
59
+ * />
60
+ * ```
61
+ *
62
+ * @returns {JSX.Element} A mesh component with the weather shader effect
63
+ */
64
+ export const WeatherEffect = (options) => {
65
+ const {
66
+ speed = signal(0.5),
67
+ windDirection = signal(0.0),
68
+ windStrength = signal(0.2),
69
+ density = signal(180.0),
70
+ resolution = signal([1000, 1000])
71
+ } = useProps(options);
72
+
73
+ // Convert to signals if not already
74
+ const speedSignal = typeof speed === 'function' ? speed : signal(speed);
75
+ const windDirectionSignal = typeof windDirection === 'function' ? windDirection : signal(windDirection);
76
+ const windStrengthSignal = typeof windStrength === 'function' ? windStrength : signal(windStrength);
77
+ const densitySignal = typeof density === 'function' ? density : signal(density);
78
+ const resolutionSignal = typeof resolution === 'function' ? resolution : signal(resolution);
79
+
80
+ // Vertex shader - handles vertex positioning and UV mapping
81
+ const vertexSrc = /* glsl */ `
82
+ precision mediump float;
83
+ attribute vec2 aPosition;
84
+ attribute vec2 aUV;
85
+ varying vec2 vUV;
86
+ void main() {
87
+ vUV = aUV;
88
+ gl_Position = vec4(aPosition, 0.0, 1.0);
89
+ }
90
+ `;
91
+
92
+ // Fragment shader - generates the rain effect
93
+ const fragmentSrc = /* glsl */ `
94
+ precision mediump float;
95
+ varying vec2 vUV;
96
+ uniform float uTime;
97
+ uniform vec2 uResolution;
98
+ uniform float uRainSpeed;
99
+ uniform float uWindDirection;
100
+ uniform float uWindStrength;
101
+ uniform float uRainDensity;
102
+
103
+ // Hash function for pseudo-random number generation
104
+ float hash(float n){ return fract(sin(n)*43758.5453); }
105
+
106
+ // Generate a single raindrop at given UV coordinates
107
+ float rainDrop(vec2 uv, float t, float seed) {
108
+ // Random X position with wider coverage for screen edges
109
+ float x = hash(seed) * 2.4 - 1.2;
110
+
111
+ // Falling speed with variation per drop
112
+ float baseSpeed = 1.0 + hash(seed + 1.0) * 1.5;
113
+ float speed = baseSpeed * uRainSpeed;
114
+
115
+ // Y position falling from top (1.0) to bottom (-1.0)
116
+ float y = 1.2 - fract(t * speed + hash(seed + 2.0)) * 2.4;
117
+
118
+ // Wind effect: more drift as drop falls further
119
+ float fallProgress = (1.2 - y) / 2.4; // 0 = top, 1 = bottom
120
+ float windOffset = uWindDirection * uWindStrength * fallProgress * 0.5;
121
+ x += windOffset;
122
+
123
+ vec2 dropPos = vec2(x, y);
124
+ vec2 diff = uv - dropPos;
125
+
126
+ // Raindrop shape (thin streaks)
127
+ float dropWidth = 0.0015 + hash(seed + 3.0) * 0.0005;
128
+ float dropLength = 0.025 + hash(seed + 4.0) * 0.015;
129
+
130
+ // Slight tilt based on wind
131
+ float windAngle = uWindDirection * uWindStrength * 0.2;
132
+ float cosA = cos(windAngle);
133
+ float sinA = sin(windAngle);
134
+ vec2 rotatedDiff = vec2(
135
+ diff.x * cosA - diff.y * sinA,
136
+ diff.x * sinA + diff.y * cosA
137
+ );
138
+
139
+ // Distance calculation for thin streaks
140
+ float distX = abs(rotatedDiff.x) / dropWidth;
141
+ float distY = abs(rotatedDiff.y) / dropLength;
142
+ float dist = max(distX, distY * 0.4);
143
+
144
+ // Intensity with fade and variation (Zelda-style)
145
+ float intensity = 1.0 - smoothstep(0.0, 1.2, dist);
146
+ intensity *= 0.7 + 0.3 * hash(seed + 5.0);
147
+
148
+ // Natural fade at top and bottom edges
149
+ intensity *= smoothstep(-1.2, -0.8, y) * smoothstep(1.2, 0.8, y);
150
+
151
+ return intensity;
152
+ }
153
+
154
+ void main(){
155
+ // Normalized UV coordinates centered on screen
156
+ vec2 uv = (gl_FragCoord.xy - 0.5 * uResolution.xy) / min(uResolution.x, uResolution.y);
157
+
158
+ float rain = 0.0;
159
+
160
+ // Generate multiple raindrops
161
+ for(float i = 0.0; i < 200.0; i++) {
162
+ rain += rainDrop(uv, uTime, i * 12.34);
163
+ }
164
+
165
+ // Adjust intensity based on density setting
166
+ rain *= (uRainDensity / 200.0);
167
+
168
+ // Zelda-style rain color (bright and visible)
169
+ vec3 rainColor = vec3(0.85, 0.9, 1.0);
170
+
171
+ gl_FragColor = vec4(rainColor * rain, rain * 0.8);
172
+ }
173
+ `;
174
+
175
+ // Create WebGL program
176
+ const glProgram = new GlProgram({ vertex: vertexSrc, fragment: fragmentSrc });
177
+
178
+ // Uniform group for shader parameters
179
+ const uniformGroup = new UniformGroup({
180
+ uTime: { value: 0, type: "f32" },
181
+ uResolution: { value: resolutionSignal(), type: "vec2<f32>" },
182
+ uRainSpeed: { value: speedSignal(), type: "f32" },
183
+ uWindDirection: { value: windDirectionSignal(), type: "f32" },
184
+ uWindStrength: { value: windStrengthSignal(), type: "f32" },
185
+ uRainDensity: { value: densitySignal(), type: "f32" },
186
+ });
187
+
188
+ // Create shader with program and resources
189
+ const shader = new Shader({
190
+ glProgram,
191
+ resources: {
192
+ uniforms: uniformGroup,
193
+ },
194
+ });
195
+
196
+ // Full-screen quad geometry
197
+ const geometry = new Geometry({
198
+ attributes: {
199
+ aPosition: [-1, -1, 1, -1, 1, 1, -1, 1],
200
+ aUV: [0, 0, 1, 0, 1, 1, 0, 1],
201
+ },
202
+ indexBuffer: [0, 1, 2, 0, 2, 3],
203
+ });
204
+
205
+ // Animation loop - update time and reactive uniforms
206
+ tick(({ deltaTime }) => {
207
+ uniformGroup.uniforms.uTime += deltaTime;
208
+
209
+ // Update uniforms from signals
210
+ uniformGroup.uniforms.uRainSpeed = speedSignal();
211
+ uniformGroup.uniforms.uWindDirection = windDirectionSignal();
212
+ uniformGroup.uniforms.uWindStrength = windStrengthSignal();
213
+ uniformGroup.uniforms.uRainDensity = densitySignal();
214
+ uniformGroup.uniforms.uResolution = resolutionSignal();
215
+ });
216
+
217
+ return h(Mesh, {
218
+ geometry,
219
+ shader,
220
+ });
221
+ };
222
+
223
+ // Export as Weather for easier usage
224
+ export const Weather = WeatherEffect;
package/src/index.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from './Bar'
2
2
  export * from './Particle'
3
3
  export * from './NightAmbiant'
4
- export * from './Joystick'
4
+ export * from './Joystick'
5
+ export * from './Tilemap'
6
+ export * from './Weathers'