@theatrejs/loader-aseprite 1.0.0 → 1.2.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/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  ## Installation
8
8
 
9
- #### `dependencies`
9
+ > *⚠️ This loader needs you to have [**Aseprite**](https://www.aseprite.org) installed.*
10
10
 
11
11
  ```shell
12
12
  npm install @theatrejs/plugin-aseprite --save
@@ -16,7 +16,7 @@ npm install @theatrejs/plugin-aseprite --save
16
16
  npm install @theatrejs/loader-aseprite --save-dev
17
17
  ```
18
18
 
19
- #### `webpack configuration`
19
+ ## Webpack Configuration
20
20
 
21
21
  ```javascript
22
22
  {
@@ -29,7 +29,43 @@ npm install @theatrejs/loader-aseprite --save-dev
29
29
  {
30
30
  'loader': '@theatrejs/loader-aseprite',
31
31
  'options': {
32
- 'aseprite': <path-to-aseprite-executable>
32
+ 'aseprite': '<path-to-aseprite>' // The path to the Aseprite executable.
33
+ }
34
+ }
35
+ ]
36
+ }
37
+ ...
38
+ ]
39
+ }
40
+ }
41
+ ```
42
+
43
+ ## Webpack Configuration (Advanced Options)
44
+
45
+ ```javascript
46
+ {
47
+ 'module': {
48
+ 'rules': [
49
+ ...
50
+ {
51
+ 'test': /\.aseprite$/,
52
+ 'use': [
53
+ {
54
+ 'loader': '@theatrejs/loader-aseprite',
55
+ 'options': {
56
+ 'aseprite': '<path-to-aseprite>', // The path to the Aseprite executable.
57
+ 'prepare': {
58
+ 'sheet': 'packed', // The Aseprite output 'sheet type' option ('colums' | 'horizontal' | 'packed' | 'rows' | 'vertical') ('rows' by default).
59
+ 'trim': true // The Aseprite output 'trim cels' option (false by default).
60
+ },
61
+ 'processing': {
62
+ 'colorswap': [
63
+ {
64
+ 'source': [255, 0, 255, 255], // A source color to swap from (in rgba).
65
+ 'target': [0, 0, 0, 0] // A target color to swap to (in rgba).
66
+ }
67
+ ]
68
+ }
33
69
  }
34
70
  }
35
71
  ]
@@ -45,16 +81,20 @@ npm install @theatrejs/loader-aseprite --save-dev
45
81
  > *⚠️ This example does not include the preloading of assets.*
46
82
 
47
83
  ```javascript
48
- import {Actor} from '@theatrejs/theatrejs';
84
+ import {Stage} from '@theatrejs/theatrejs';
85
+ import * as PLUGINASEPRITE from '@theatrejs/plugin-aseprite';
49
86
 
50
- import spritesheetHero from './hero-16x16.aseprite';
87
+ import asepriteHero from './hero-16x16.aseprite';
51
88
 
52
- class Hero extends Actor {
89
+ class Level1 extends Stage {
53
90
  onCreate() {
54
- this.$timeline = spritesheetHero.createTimeline({$actor: this, $framerate: 8, $loop: true, $tag: 'idle'});
55
- }
56
- onTick($timetick) {
57
- this.$timeline.tick($timetick);
91
+ this.createActor(
92
+ PLUGINASEPRITE.FACTORIES.ActorWithSpritesheet({
93
+ $aseprite: asepriteHero,
94
+ $loop: true,
95
+ $tag: 'idle'
96
+ })
97
+ );
58
98
  }
59
99
  }
60
100
  ```
@@ -63,19 +103,19 @@ class Hero extends Actor {
63
103
 
64
104
  ```javascript
65
105
  import {FACTORIES} from '@theatrejs/theatrejs';
66
-
67
106
  import * as PLUGINASEPRITE from '@theatrejs/plugin-aseprite';
68
107
 
69
- import spritesheetHero from './hero-16x16.aseprite';
108
+ import asepriteHero from './hero-16x16.aseprite';
70
109
 
71
- class Hero extends FACTORIES.ActorWithPreloadables([PLUGINASEPRITE.FACTORIES.PreloadableAseprite(spritesheetHero)]) {
110
+ class Level1 extends FACTORIES.StageWithPreloadables([PLUGINASEPRITE.FACTORIES.PreloadableAseprite(asepriteHero)]) {
72
111
  onCreate() {
73
- this.$timeline = spritesheetHero.createTimeline({$actor: this, $framerate: 8, $loop: true, $tag: 'idle'});
74
- }
75
- onTick($timetick) {
76
- this.$timeline.tick($timetick);
112
+ this.createActor(
113
+ PLUGINASEPRITE.FACTORIES.ActorWithSpritesheet({
114
+ $aseprite: asepriteHero,
115
+ $loop: true,
116
+ $tag: 'idle'
117
+ })
118
+ );
77
119
  }
78
120
  }
79
121
  ```
80
-
81
- ## [API](https://theatrejs.github.io/loader-aseprite/index.html)
package/package.json CHANGED
@@ -1,15 +1,26 @@
1
1
  {
2
2
  "author": "Alexandre Blondeau",
3
+ "dependencies": {
4
+
5
+ "pngjs": "7.0.0"
6
+ },
3
7
  "description": "⚙️ A Webpack Loader for Aseprite files.",
8
+ "devDependencies": {
9
+
10
+ "@types/pngjs": "6.0.5"
11
+ },
4
12
  "engines": {
13
+
5
14
  "node": "16.13.0",
6
15
  "npm": "8.1.0"
7
16
  },
8
17
  "files": [
18
+
9
19
  "sources/"
10
20
  ],
11
21
  "homepage": "https://github.com/theatrejs/loader-aseprite",
12
22
  "keywords": [
23
+
13
24
  "2d",
14
25
  "aseprite",
15
26
  "canvas",
@@ -32,13 +43,19 @@
32
43
  "main": "./sources/index.js",
33
44
  "name": "@theatrejs/loader-aseprite",
34
45
  "peerDependencies": {
35
- "@theatrejs/plugin-aseprite": ">= 1.0.0",
46
+
47
+ "@theatrejs/plugin-aseprite": ">= 1.1.0",
36
48
  "webpack": ">= 5.94.0"
37
49
  },
38
50
  "repository": {
51
+
39
52
  "type": "git",
40
53
  "url": "git+https://github.com/theatrejs/loader-aseprite.git"
41
54
  },
55
+ "scripts": {
56
+
57
+ "postversion": "node ./tools/custom/postversion.cjs"
58
+ },
42
59
  "type": "commonjs",
43
- "version": "1.0.0"
60
+ "version": "1.2.0"
44
61
  }
@@ -4,14 +4,28 @@ const path = require('path');
4
4
 
5
5
  const webpack = require('webpack');
6
6
 
7
+ const pngjs = require('pngjs').PNG.sync;
8
+
7
9
  /**
8
10
  * @type {webpack.RawLoaderDefinition}
9
11
  */
10
12
  module.exports = function loader() {
11
13
 
12
14
  /**
13
- * @typedef {Object} typeoptions Options for the loader.
14
- * @property {(string | undefined)} typeoptions.aseprite The path of the Aseprite executable.
15
+ * @typedef {Object} typecolorswap A swap of two colors.
16
+ * @property {Array<number>} typecolorswap.source The source color to swap from (in rgba).
17
+ * @property {Array<number>} typecolorswap.target The target color to swap to (in rgba).
18
+ * @private
19
+ */
20
+
21
+ /**
22
+ * @typedef {Object} typeoptions The options for the loader.
23
+ * @property {string} typeoptions.aseprite The path to the Aseprite executable.
24
+ * @property {Object} [typeoptions.prepare] The options for the Aseprite CLI.
25
+ * @property {('colums' | 'horizontal' | 'packed' | 'rows' | 'vertical')} [typeoptions.prepare.sheet] The output sheet type ('rows' by default).
26
+ * @property {boolean} [typeoptions.prepare.trim] The 'trim cels' option (false by default).
27
+ * @property {Object} [typeoptions.processing] The options for processing the output files.
28
+ * @property {Array<typecolorswap>} [typeoptions.processing.colorswap] The swaps of colors.
15
29
  * @private
16
30
  */
17
31
 
@@ -20,6 +34,8 @@ module.exports = function loader() {
20
34
  const file = context.resourcePath;
21
35
  const options = context.getOptions();
22
36
  const aseprite = options.aseprite;
37
+ const prepare = options.prepare;
38
+ const processing = options.processing;
23
39
 
24
40
  try {
25
41
 
@@ -43,8 +59,11 @@ module.exports = function loader() {
43
59
 
44
60
  const location = path.dirname(file);
45
61
  const filename = path.basename(file, '.aseprite');
46
- const png = filename + '.png';
47
- const json = filename + '.json';
62
+ const sourceTexture = filename + '.png';
63
+ const sourceData = filename + '.json';
64
+
65
+ const trim = (typeof prepare !== 'undefined' && prepare.trim === true) ? ' --trim' : '';
66
+ const sheetType = (typeof prepare !== 'undefined' && ['colums', 'horizontal', 'packed', 'rows', 'vertical'].indexOf(prepare.sheet) !== -1) ? prepare.sheet : 'rows';
48
67
 
49
68
  try {
50
69
 
@@ -54,21 +73,67 @@ module.exports = function loader() {
54
73
 
55
74
  ' && "' + aseprite + '"' +
56
75
  ' --batch "' + file + '"' +
57
- ' --sheet "' + png + '"' +
58
- ' --sheet-type rows' +
76
+ trim +
77
+ ' --sheet "' + sourceTexture + '"' +
78
+ ' --sheet-type ' + sheetType +
59
79
  ' --split-tags' +
60
- ' --data "' + json + '"' +
80
+ ' --data "' + sourceData + '"' +
61
81
  ' --list-tags' +
62
82
  ' --format json-array' +
63
83
  ' --filename-format {tag}#{tagframe001}@{title}.{extension}'
64
84
  );
65
85
 
86
+ if (typeof processing !== 'undefined'
87
+ && Array.isArray(processing.colorswap)
88
+ && processing.colorswap.length > 0) {
89
+
90
+ const bufferSource = fs.readFileSync(path.resolve(location, sourceTexture));
91
+ const image = pngjs.read(bufferSource);
92
+
93
+ const pixels = image.data;
94
+ const height = image.height;
95
+ const width = image.width;
96
+
97
+ processing.colorswap.forEach(({source, target}) => {
98
+
99
+ const [redSource, greenSource, blueSource, alphaSource] = source;
100
+ const [redTarget, greenTarget, blueTarget, alphaTarget] = target;
101
+
102
+ for (let y = 0; y < height; y += 1) {
103
+
104
+ for (let x = 0; x < width; x += 1) {
105
+
106
+ const index = (width * y + x) * 4;
107
+
108
+ const indexRed = index;
109
+ const indexGreen = index + 1;
110
+ const indexBlue = index + 2;
111
+ const indexAlpha = index + 3;
112
+
113
+ if (pixels[indexRed] === redSource
114
+ && pixels[indexGreen] === greenSource
115
+ && pixels[indexBlue] === blueSource
116
+ && pixels[indexAlpha] === alphaSource) {
117
+
118
+ pixels[indexRed] = redTarget;
119
+ pixels[indexGreen] = greenTarget;
120
+ pixels[indexBlue] = blueTarget;
121
+ pixels[indexAlpha] = alphaTarget;
122
+ }
123
+ }
124
+ }
125
+ });
126
+
127
+ const bufferTarget = pngjs.write(image);
128
+ fs.writeFileSync(path.resolve(location, sourceTexture), bufferTarget);
129
+ }
130
+
66
131
  return (
67
132
 
68
133
  'import {Aseprite} from \'@theatrejs/plugin-aseprite\';' +
69
134
 
70
- 'import texture from \'./' + png + '\';' +
71
- 'import data from \'./' + json + '\';' +
135
+ 'import data from \'./' + sourceData + '\';' +
136
+ 'import texture from \'./' + sourceTexture + '\';' +
72
137
 
73
138
  'export default new Aseprite(texture, data);'
74
139
  );