@tawaship/pixi-animate-runtime 0.0.0-stage → 0.1.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.
- package/LICENSE +21 -0
- package/README.md +462 -2
- package/bin/pixi-animate-runtime.js +27 -0
- package/dist/generator.cjs.js +1056 -0
- package/dist/generator.cjs.js.map +1 -0
- package/dist/pixi-animate-runtime.cjs.js +3742 -0
- package/dist/pixi-animate-runtime.cjs.js.map +1 -0
- package/dist/pixi-animate-runtime.esm.js +3677 -0
- package/dist/pixi-animate-runtime.esm.js.map +1 -0
- package/dist/pixi-animate-runtime.js +3744 -0
- package/dist/pixi-animate-runtime.js.map +1 -0
- package/dist-skills/animate-data-converter-guide/SKILL.md +86 -0
- package/dist-skills/pixi-animate-runtime-guide/SKILL.md +146 -0
- package/package.json +70 -4
- package/tools/pixi-animate-runtime.bat +8 -0
- package/types/generator/generator/cli.d.ts +17 -0
- package/types/generator/generator/converter-version.d.ts +7 -0
- package/types/generator/generator/generate.d.ts +33 -0
- package/types/generator/generator/index.d.ts +6 -0
- package/types/generator/generator/plan.d.ts +87 -0
- package/types/generator/player/data.d.ts +141 -0
- package/types/generator/player/ease.d.ts +11 -0
- package/types/generator/player/semver.d.ts +27 -0
- package/types/generator/player/version.d.ts +2 -0
- package/types/player/animate-container.d.ts +73 -0
- package/types/player/content.d.ts +181 -0
- package/types/player/data.d.ts +141 -0
- package/types/player/display.d.ts +192 -0
- package/types/player/ease.d.ts +11 -0
- package/types/player/events.d.ts +60 -0
- package/types/player/geom.d.ts +19 -0
- package/types/player/index.d.ts +20 -0
- package/types/player/loader.d.ts +53 -0
- package/types/player/movieclip.d.ts +191 -0
- package/types/player/objects.d.ts +320 -0
- package/types/player/semver.d.ts +27 -0
- package/types/player/transform.d.ts +32 -0
- package/types/player/version.d.ts +2 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 tawaship
|
|
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
CHANGED
|
@@ -1,3 +1,463 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @tawaship/pixi-animate-runtime
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Plays content made in Adobe Animate (published for HTML5 Canvas) on PixiJS, without CreateJS.
|
|
4
|
+
|
|
5
|
+
- **Convert once, at development time**: a command turns the files Animate publishes into an optimized
|
|
6
|
+
*runtime content* file
|
|
7
|
+
- **Play the runtime content in your PixiJS application**: the player plays it as CreateJS would, without
|
|
8
|
+
CreateJS and without the published files
|
|
9
|
+
- **What it brings**: creating many instances at once stays light (each symbol is prepared once and shared),
|
|
10
|
+
playback stays even when frame times vary, and what is played is checked frame by frame against CreateJS
|
|
11
|
+
|
|
12
|
+
Coming from [@tawaship/pixi-animate-container](https://github.com/tawaship/pixi-animate-container)? It plays the
|
|
13
|
+
same content and is used the same way; see [Coming from pixi-animate-container](#coming-from-pixi-animate-container).
|
|
14
|
+
|
|
15
|
+
**Status: under development.** What does not work yet is listed under [Current limits](#current-limits).
|
|
16
|
+
|
|
17
|
+
API reference: https://tawaship.github.io/pixi-animate-runtime/docs/
|
|
18
|
+
|
|
19
|
+
Samples (content published from Animate, played by this package or by CreateJS): https://tawaship.github.io/pixi-animate-runtime/samples/
|
|
20
|
+
|
|
21
|
+
**Convert only content you trust.** Converting runs the published JavaScript, frame scripts included, to read
|
|
22
|
+
it. It runs in a sandbox (QuickJS, a separate JavaScript engine compiled to WebAssembly) that is given nothing
|
|
23
|
+
of your machine: no files, no commands, no network. Running code is never without risk all the same: a flaw in
|
|
24
|
+
the sandbox or the engines could let code in the file reach further. Convert content published by you or by
|
|
25
|
+
people you trust, and treat content you receive (from a contractor, an asset store and so on) as code you would
|
|
26
|
+
run. In the browser, the runtime content is as safe as the published content would be.
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
The published files are needed only to convert. Your application ships the runtime content (and the images it
|
|
31
|
+
uses), not the published files. This example keeps them apart:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
my-project/
|
|
35
|
+
├─ animate/ what Animate publishes (read when converting; not shipped)
|
|
36
|
+
└─ public/ what the application ships
|
|
37
|
+
├─ animates/ the runtime content, written by the command
|
|
38
|
+
├─ lib/ PixiJS and the player
|
|
39
|
+
└─ index.html
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
1. **Publish from Animate.** In Adobe Animate, publish the document for HTML5 Canvas into `animate/` (you get
|
|
43
|
+
`game.js`, `game.html` and an `images/` directory).
|
|
44
|
+
|
|
45
|
+
2. **Install.** In the project (Node.js 18 or later):
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
npm install pixi.js@5 @tawaship/pixi-animate-runtime
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Copy `node_modules/pixi.js/dist/pixi.min.js` and
|
|
52
|
+
`node_modules/@tawaship/pixi-animate-runtime/dist/pixi-animate-runtime.js` into `public/lib/` (or import the
|
|
53
|
+
player with a bundler).
|
|
54
|
+
|
|
55
|
+
3. **Convert.** From the project's root:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
npx --no-install @tawaship/pixi-animate-runtime animate --out-dir public/animates
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
It lists what it will write and asks; answer `y`. This writes `public/animates/game.js` (the runtime
|
|
62
|
+
content) and copies the images it uses into `public/animates/images/`. The list shows the content's
|
|
63
|
+
**composition id**, which the next step needs.
|
|
64
|
+
|
|
65
|
+
4. **Play.** In `public/index.html`, load PixiJS, the player and the runtime content, and put the symbol the
|
|
66
|
+
published HTML showed (named after the published file, here `game`) on an `AnimateContainer`:
|
|
67
|
+
|
|
68
|
+
```html
|
|
69
|
+
<script src="lib/pixi.min.js"></script>
|
|
70
|
+
<script src="lib/pixi-animate-runtime.js"></script>
|
|
71
|
+
<script src="animates/game.js"></script>
|
|
72
|
+
<script>
|
|
73
|
+
const app = new PIXI.Application({ width: 550, height: 400 });
|
|
74
|
+
document.body.appendChild(app.view);
|
|
75
|
+
|
|
76
|
+
const { loadContentAsync, AnimateContainer } = PIXI.animateRuntime;
|
|
77
|
+
loadContentAsync({ id: '<composition id>', basepath: 'animates/' }).then(content => {
|
|
78
|
+
const container = new AnimateContainer();
|
|
79
|
+
app.stage.addChild(container);
|
|
80
|
+
app.ticker.add(container.handleTick, container);
|
|
81
|
+
container.addCreatejs(content.create('game'));
|
|
82
|
+
});
|
|
83
|
+
</script>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The content plays at the frame rate it was published with.
|
|
87
|
+
|
|
88
|
+
5. **After publishing again from Animate, run step 3 again.** The player plays the runtime content, never the
|
|
89
|
+
published files: a change made in Animate shows only once the runtime content is made again.
|
|
90
|
+
|
|
91
|
+
The sections below explain each step: [Converting published content](#converting-published-content) (options,
|
|
92
|
+
the Windows batch file, the Node API) and [Playing content](#playing-content) (loading options, the container,
|
|
93
|
+
the objects).
|
|
94
|
+
|
|
95
|
+
## What you need
|
|
96
|
+
|
|
97
|
+
- PixiJS 5.3 (`pixi.js` ^5.3.2) in your application
|
|
98
|
+
- Node.js 18 or later to convert the published file (the conversion does not run in the browser)
|
|
99
|
+
|
|
100
|
+
## Supported versions
|
|
101
|
+
|
|
102
|
+
- Content published by **Adobe Animate 24.0.15** for HTML5 Canvas. What this package reads is the form of the published
|
|
103
|
+
JavaScript, which depends on the version of Animate; content published by other versions has not been checked
|
|
104
|
+
- PixiJS 5.3 (`pixi.js` ^5.3.2). Checked with 5.3.9
|
|
105
|
+
|
|
106
|
+
## Converting published content
|
|
107
|
+
|
|
108
|
+
Turn the published content into runtime content with the command line tool, giving it the directory Animate
|
|
109
|
+
published into (the one with the published `.js` files; `.fla` files and an `images/` directory there are
|
|
110
|
+
optional):
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
npx --no-install @tawaship/pixi-animate-runtime assets/animates
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`--no-install` runs only the copy installed in your project: without it, `npx` would download and run a package from the npm registry when the command is not installed. In the `scripts` of your `package.json`, the command name alone is enough (`"animate": "pixi-animate-runtime animate -o public/animates"`): npm runs scripts with the commands installed in the project and downloads nothing.
|
|
117
|
+
|
|
118
|
+
To keep `npx` from downloading anything in your project at all (also when `--no-install` is forgotten), put
|
|
119
|
+
`yes=false` in the project's `.npmrc`. `npx` then stops with an error when a command is not installed, instead
|
|
120
|
+
of asking or, where nobody can answer (CI, scripts), downloading it without asking.
|
|
121
|
+
|
|
122
|
+
This writes, into `assets/animates/generated/`, one runtime content file for every published JavaScript file
|
|
123
|
+
in the directory, under the same name (`game.js` to `generated/game.js`), and copies the images each content
|
|
124
|
+
uses next to it at the same relative paths (`generated/images/...`). Images left over from earlier publishes
|
|
125
|
+
that no content uses are not copied, and scripts that are not Animate output are left alone. Copy the whole
|
|
126
|
+
`generated/` directory into your application's assets.
|
|
127
|
+
|
|
128
|
+
| Argument / option | Effect |
|
|
129
|
+
|---|---|
|
|
130
|
+
| a published `.js` file instead of a directory | Converts that file only |
|
|
131
|
+
| `-o, --out-dir <directory>` | Writes straight into that directory instead of `generated/` |
|
|
132
|
+
| `-r, --recursive` | Also converts the published files in the directories below (not in `node_modules`, nor in directories whose name starts with `.`). With `-o`, each is written below that directory at the same relative path (`title/title.js` to `<directory>/title/title.js`); without it, into `generated/` next to its published file |
|
|
133
|
+
| `-y, --yes` | Writes without asking anything (directories not given take their defaults). Needed when run from a script or CI |
|
|
134
|
+
| `-f, --force` | Writes runtime content even when the content uses features that are not supported |
|
|
135
|
+
| `-h, --help` | Shows the usage |
|
|
136
|
+
|
|
137
|
+
Before writing anything, the tool lists where it reads from and writes to, then a row for each published file:
|
|
138
|
+
its composition id, the number of images it uses, and whether it is new, replaces a file already there, or is
|
|
139
|
+
not written (and why):
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
From: assets/animates
|
|
143
|
+
To: generated/ next to each published file
|
|
144
|
+
|
|
145
|
+
published composition id images
|
|
146
|
+
game.js 2FA8E0C7... 3 new
|
|
147
|
+
title.js D6D50362... 1 replace
|
|
148
|
+
old.js B3DEAFD3... not written: images it uses are missing: images/old_atlas_1.png
|
|
149
|
+
|
|
150
|
+
2 to write, 1 not written.
|
|
151
|
+
Write these? (y/N):
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Composition ids are shortened in this list; the whole id is in the published file (`lib.properties.id`) and at
|
|
155
|
+
the top of the runtime content file.
|
|
156
|
+
|
|
157
|
+
Nothing is written unless you answer `y`. Run from a script or CI, where nobody can answer (not a terminal),
|
|
158
|
+
it only lists and writes nothing unless `-y` is given; with `-y`, it asks nothing and writes. Run in a terminal
|
|
159
|
+
without a directory (and without `-y`), the tool first asks for it, lists the published files it found, and
|
|
160
|
+
asks where to write (empty: `generated/`).
|
|
161
|
+
|
|
162
|
+
Nothing is ever deleted: files already in the output directory that the run did not write are listed, for you
|
|
163
|
+
to remove when they are no longer needed.
|
|
164
|
+
|
|
165
|
+
A content is not written when it uses unsupported features (each one is listed), when an image it uses is
|
|
166
|
+
missing, or when the path of an image leads out of the published directory (Animate writes them below it);
|
|
167
|
+
the other contents still are, and the command then exits with `1`. It exits with `2` when the directory or
|
|
168
|
+
file cannot be read.
|
|
169
|
+
|
|
170
|
+
On Windows, `tools/pixi-animate-runtime.bat` (in the installed package) does the same: copy it into your
|
|
171
|
+
project, then drop the published directory on it, or double-click it to be asked.
|
|
172
|
+
|
|
173
|
+
The same is available from Node, in two steps, so that a script of your own can show the plan, ask its own
|
|
174
|
+
questions or choose what to write in between:
|
|
175
|
+
|
|
176
|
+
```js
|
|
177
|
+
const { planGeneration, writeGeneration } = require('@tawaship/pixi-animate-runtime/generator');
|
|
178
|
+
|
|
179
|
+
planGeneration({ input: 'assets/animates', outDir: 'public/animates', recursive: true }).then(plan => {
|
|
180
|
+
plan.contents.forEach(content => {
|
|
181
|
+
console.log(content.name, '->', content.out, content.problem || '');
|
|
182
|
+
});
|
|
183
|
+
const result = writeGeneration(plan);
|
|
184
|
+
console.log(result.written.length + ' file(s) written');
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
`planGeneration(options)` takes what the command line takes (`input`, `outDir`, `recursive`, `force`, `cwd`),
|
|
189
|
+
makes the runtime content and works out where everything goes, but writes nothing. Each of `plan.contents` is
|
|
190
|
+
one published file: `name`, `id` (composition id), `out` (where it goes), `exists` (a file is already there),
|
|
191
|
+
`images` (`from` and `to`), `issues`, `warnings`, and `problem`, the reason it is not written (`null` when it
|
|
192
|
+
is). `writeGeneration(plan)` writes the runtime content as the plan made it (a published file changed in
|
|
193
|
+
between does not change what is written), copies the images, and returns `written` (the files it wrote) and
|
|
194
|
+
`left` (the files already in the output directories that it did not write). It deletes nothing. To write only some of the contents, give it a plan with
|
|
195
|
+
the others removed from `contents`.
|
|
196
|
+
|
|
197
|
+
For one published file without writing anything:
|
|
198
|
+
|
|
199
|
+
```js
|
|
200
|
+
const { generateFromPublishedFile } = require('@tawaship/pixi-animate-runtime/generator');
|
|
201
|
+
|
|
202
|
+
generateFromPublishedFile('assets/animates/game.js').then(generated => {
|
|
203
|
+
require('fs').writeFileSync('game.js', generated.source);
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
`generated.id` is the content's composition id, `generated.data` its data, `generated.issues` lists
|
|
208
|
+
unsupported features and `generated.warnings` what to look at (see [Versions](#versions)). Images are not
|
|
209
|
+
copied by this function.
|
|
210
|
+
|
|
211
|
+
`generate(definition)` makes the runtime content from a definition you already have, in the form
|
|
212
|
+
`@tawaship/animate-data-converter` extracts it (its compact form). An expanded definition (written with
|
|
213
|
+
`--expanded`, or made with `expand()`) is refused: turn it back with the converter's `compact()` first.
|
|
214
|
+
|
|
215
|
+
Frame scripts are copied into the runtime content as they were published, as code. Nothing is rewritten
|
|
216
|
+
(a `console.log` left in a script stays), and the runtime content needs no `eval` at run time.
|
|
217
|
+
|
|
218
|
+
### Composition ids
|
|
219
|
+
|
|
220
|
+
A runtime content file registers itself, when it is loaded, under the content's **composition id**: the
|
|
221
|
+
`lib.properties.id` of the published content, the id Animate gives a document when the `.fla` is created. The
|
|
222
|
+
player takes the content by this id.
|
|
223
|
+
|
|
224
|
+
- Copying a `.fla` keeps its composition id, so two contents made that way share one id. Create a new document
|
|
225
|
+
for a new content (the id can also be changed by editing the XML inside the `.fla`)
|
|
226
|
+
- Loading a runtime content file whose id is already registered replaces the earlier one, with a warning on the
|
|
227
|
+
console. Contents already built from the earlier one keep working; contents loaded afterwards use the new one.
|
|
228
|
+
This lets an application load contents of the same make (the same symbols, different looks) under one id in
|
|
229
|
+
turn. Two different contents with one id are not told apart: if their symbols share names, the later content
|
|
230
|
+
is shown where the earlier was meant
|
|
231
|
+
|
|
232
|
+
## Playing content
|
|
233
|
+
|
|
234
|
+
Load the runtime content file, load the content by its composition id, and put an instance of a symbol on an
|
|
235
|
+
`AnimateContainer`:
|
|
236
|
+
|
|
237
|
+
```html
|
|
238
|
+
<script src="pixi.js"></script>
|
|
239
|
+
<script src="pixi-animate-runtime.js"></script>
|
|
240
|
+
<script src="assets/animates/game.js"></script> <!-- a runtime content file -->
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
```js
|
|
244
|
+
const { loadContentAsync, AnimateContainer } = PIXI.animateRuntime;
|
|
245
|
+
|
|
246
|
+
loadContentAsync({ id: '2FA8E0C7230941478CE2CA3DB82DBEDF', basepath: 'assets/animates/' })
|
|
247
|
+
.then(content => {
|
|
248
|
+
const container = new AnimateContainer();
|
|
249
|
+
app.stage.addChild(container);
|
|
250
|
+
app.ticker.add(container.handleTick, container);
|
|
251
|
+
|
|
252
|
+
container.addCreatejs(content.create('game')); // the symbol the published HTML used as its root
|
|
253
|
+
});
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
This loads the content's images from `basepath` and shows the `game` symbol, playing it at the frame rate it
|
|
257
|
+
was published with, whatever the display's refresh rate: `handleTick` turns the ticker's time into the
|
|
258
|
+
content's frames.
|
|
259
|
+
|
|
260
|
+
- Runtime content files are loaded by you, before `loadContentAsync`: with script tags as above, or by adding
|
|
261
|
+
script elements at run time. They register into `window.PixiAnimateRuntimeContents` and can be loaded
|
|
262
|
+
before or after the player
|
|
263
|
+
- `id` is the composition id (the command line tool prints it, and it is written at the top of the runtime
|
|
264
|
+
content file). When no content is registered under it, the error lists the ones that are
|
|
265
|
+
- `basepath` is the directory the content's image paths are relative to: where the runtime content file was
|
|
266
|
+
written, ending with `/`. `options: { crossOrigin: false }` loads the images without CORS (requested with
|
|
267
|
+
CORS, anonymous, by default)
|
|
268
|
+
- `options: { handleManifest(manifest) { ... } }` is called with the content's images (`{ id, src }`, `src` as
|
|
269
|
+
published) before they are loaded. Changing an entry's `src` changes what this load reads: a `data:` or
|
|
270
|
+
`blob:` URL is used as it is, another path is resolved against `basepath`. It may return a promise to make the
|
|
271
|
+
loading wait
|
|
272
|
+
- The second argument, `{ version }`, adds `_fv=<version>` to every image URL to bypass caches; the query
|
|
273
|
+
Animate adds to each image path on every publish stays
|
|
274
|
+
- An array of targets loads several contents, giving an array of contents
|
|
275
|
+
- `create(id)` creates an instance of any symbol, set up the way the published HTML sets up the root it
|
|
276
|
+
creates: use it for the instances your application places. `content.lib` holds the symbol classes;
|
|
277
|
+
`new content.lib.game()` creates an instance the way a frame script does, without that setup (it only
|
|
278
|
+
matters for color effects, which the player draws the same either way)
|
|
279
|
+
- `content.id` is the composition id, and `content.properties` holds the values of the published
|
|
280
|
+
`lib.properties` (`width`, `height`, `fps`, `color` and so on; read-only)
|
|
281
|
+
- To use an image of the content elsewhere, create the symbol that shows it and take its Pixi node:
|
|
282
|
+
`content.create('Bitmap1').pixi.texture`
|
|
283
|
+
- `container.speed` changes the playback speed (`1` is the published frame rate, `0` stops; a value below `0`
|
|
284
|
+
stops it as `0` does, and it goes on from where it stopped once the speed is above `0` again). When the
|
|
285
|
+
display runs slower than the content, one call plays several frames; set `container.overSpeed = false`
|
|
286
|
+
to play at most one frame per call
|
|
287
|
+
- `container.smooth` (`true` by default) keeps the playing even when the time between frames of the display
|
|
288
|
+
varies a little: the frames follow a steady clock (the usual time between frames of the display), so a
|
|
289
|
+
display frame coming a little early or late does not leave one call with no frame and the next with two.
|
|
290
|
+
The clock keeps to the real time, and frames the display misses are still caught up at once. `false`
|
|
291
|
+
plays by the time of each call as it is, as pixi-animate-container does
|
|
292
|
+
- A movie clip starts from its first frame when it is put on the container. `removeCreatejs(instance)`
|
|
293
|
+
takes it off, and it stops playing
|
|
294
|
+
- `tick(instance)` plays exactly one frame, for stepping through content by hand
|
|
295
|
+
- To play roots on a container of your own (of another framework built on PixiJS), give it an
|
|
296
|
+
`AnimateController`: `new AnimateController(container)` has the `addCreatejs`, `handleTick`, `speed`,
|
|
297
|
+
`overSpeed` and `smooth` of `AnimateContainer`, putting the instances on that container
|
|
298
|
+
|
|
299
|
+
For Pixim.js applications, use [@tawaship/pixim-animate-runtime](https://github.com/tawaship/Pixim-animate-runtime): it
|
|
300
|
+
includes this player and loads contents as assets of a Pixim content.
|
|
301
|
+
|
|
302
|
+
With a bundler, import the player instead (`import { loadContentAsync } from '@tawaship/pixi-animate-runtime'`);
|
|
303
|
+
the runtime content files are still loaded as scripts.
|
|
304
|
+
|
|
305
|
+
### Objects and their Pixi nodes
|
|
306
|
+
|
|
307
|
+
Every instance is a CreateJS-compatible object (what frame scripts see as `this`), shown by a PixiJS node
|
|
308
|
+
in its `pixi` property. Values the two have in common are kept in one place: `instance.x = 100` and
|
|
309
|
+
`instance.pixi.x = 100` are the same write, and what the timeline does with it afterwards is what
|
|
310
|
+
CreateJS would do.
|
|
311
|
+
|
|
312
|
+
Members whose meaning differs between CreateJS and PixiJS keep the CreateJS meaning on the instance and
|
|
313
|
+
the PixiJS meaning on its node:
|
|
314
|
+
|
|
315
|
+
| Member | On the instance | On `instance.pixi` |
|
|
316
|
+
|---|---|---|
|
|
317
|
+
| `rotation` | Degrees | Radians (`angle` is degrees) |
|
|
318
|
+
| `skewX` / `skewY` | Degrees, CreateJS skew | `skew` in radians |
|
|
319
|
+
| `mask`, `filters`, `parent`, `children` | CreateJS objects | PixiJS objects |
|
|
320
|
+
|
|
321
|
+
Shapes that show the same drawing share one PixiJS geometry, even across symbols. Do not draw into the
|
|
322
|
+
`pixi` node of a shape (`graphics.clear()`, `lineTo()` and so on): the change would show in every shape that
|
|
323
|
+
shares the drawing.
|
|
324
|
+
|
|
325
|
+
Rotation and skew combine the way CreateJS combines them (the object is rotated first and then skewed),
|
|
326
|
+
which matches what the published content shows in a browser.
|
|
327
|
+
|
|
328
|
+
Dynamic text breaks into lines the way the published content does: a line wider than the text box is broken
|
|
329
|
+
at spaces only, so a long word, or text without spaces such as Japanese, runs past the box. Animate's own
|
|
330
|
+
stage breaks such text inside words, so the two can look different; the player follows the published
|
|
331
|
+
content.
|
|
332
|
+
|
|
333
|
+
Frame scripts can use the names published code uses: `this`, `cjs` / `createjs` (the player's
|
|
334
|
+
CreateJS-compatible classes), and `lib` (the symbol classes). `exportRoot` and `stage` are undefined.
|
|
335
|
+
`playSound()` plays nothing.
|
|
336
|
+
|
|
337
|
+
## Coming from pixi-animate-container
|
|
338
|
+
|
|
339
|
+
pixi-animate-container loads CreateJS and the published JavaScript in the browser, runs them, and shows the
|
|
340
|
+
CreateJS display objects through PixiJS. This package does the CreateJS part once, at development time:
|
|
341
|
+
|
|
342
|
+
- In the browser, only PixiJS, the player and the runtime content files are loaded. CreateJS and the
|
|
343
|
+
published JavaScript are not
|
|
344
|
+
- After publishing again from Animate, generate the runtime content again: the player does not read the
|
|
345
|
+
published file
|
|
346
|
+
- Each symbol is defined once and shared by every instance, instead of each instance building its own
|
|
347
|
+
timeline when it is created
|
|
348
|
+
|
|
349
|
+
The way content is put on the screen stays the same, under new names:
|
|
350
|
+
|
|
351
|
+
| pixi-animate-container | pixi-animate-runtime |
|
|
352
|
+
|---|---|
|
|
353
|
+
| `<script>` tags for CreateJS and the published `.js` | A `<script>` tag for the runtime content file (no CreateJS) |
|
|
354
|
+
| `PIXI.animate` | `PIXI.animateRuntime` |
|
|
355
|
+
| `loadAssetAsync(targets)`, giving `lib` | `loadContentAsync(targets)`, giving a content (its classes are in `content.lib`) |
|
|
356
|
+
| `new lib.game()` | `content.create('game')` (`new content.lib.game()` also works, see [Playing content](#playing-content)) |
|
|
357
|
+
| `PIXI.animate.Container` | `AnimateContainer` |
|
|
358
|
+
| `addCreatejs`, `addCreatejsAt`, `removeCreatejs`, `handleTick` | The same |
|
|
359
|
+
| `createjsSpeed` | `speed` |
|
|
360
|
+
| `createjsOverSpeed` | `overSpeed` |
|
|
361
|
+
| (none) | `smooth`: even playing when the time between frames varies (on by default; `false` plays as pixi-animate-container does) |
|
|
362
|
+
| `options: { crossOrigin }` | The same |
|
|
363
|
+
| `CreatejsMovieClip`, `CreatejsShape` and the other wrapper classes | `MovieClip`, `Shape` and the other CreateJS-compatible classes; `instance.pixi` is still the PixiJS node |
|
|
364
|
+
|
|
365
|
+
What behaves differently:
|
|
366
|
+
|
|
367
|
+
- `instance.pixi` is always current. The instance and its node share their values (see
|
|
368
|
+
[Objects and their Pixi nodes](#objects-and-their-pixi-nodes)), so a frame script reading `instance.pixi.x`
|
|
369
|
+
gets the value just written, not the value of the previous frame
|
|
370
|
+
- Not available: `options.listenFrameEvents` (`endAnimation`, `reachLabel`), `options.useSound` (sound is not
|
|
371
|
+
played), and CreateJS mouse events on instances (see [Current limits](#current-limits))
|
|
372
|
+
|
|
373
|
+
## Current limits
|
|
374
|
+
|
|
375
|
+
- Buttons do not react to the pointer: a button shows its idle ("up") frame and stays there. Listeners for
|
|
376
|
+
CreateJS mouse events (`mousedown`, `click`, `rollover` and so on) are not called. To react to the
|
|
377
|
+
pointer, listen to PixiJS events on the instance's `pixi` node (`pointerdown`, `pointertap`,
|
|
378
|
+
`pointerover` and so on, with `interactive = true`). Masks are never hit by the pointer
|
|
379
|
+
- Dynamic text is provisional. Lines break as in the published content (see above). Depending on the font,
|
|
380
|
+
text sits slightly higher than in the published content. Paragraph indents and margins set in Animate are not
|
|
381
|
+
in the published content and have no effect. `textBaseline` other than `top`, `maxWidth` and `outline` are
|
|
382
|
+
not checked yet
|
|
383
|
+
- Sound is not played
|
|
384
|
+
- Content that uses the Animate camera ("Advanced Layers") is not supported: delete the camera layer and
|
|
385
|
+
publish again
|
|
386
|
+
|
|
387
|
+
## How it works
|
|
388
|
+
|
|
389
|
+
Published content defines each symbol as a class whose constructor builds its children and its whole timeline,
|
|
390
|
+
for every instance. The command runs the published code once, at development time (in its sandbox, with
|
|
391
|
+
`@tawaship/animate-data-converter`), and records each symbol as data: the display objects it owns and the
|
|
392
|
+
value of every property its timeline sets, at every frame. The runtime content holds that data, written
|
|
393
|
+
compactly, and the frame scripts as code.
|
|
394
|
+
|
|
395
|
+
The player builds every instance of a symbol from the same data, so creating many instances at once does not
|
|
396
|
+
build a timeline for each, and it needs neither CreateJS nor the published code. It plays the frames as CreateJS
|
|
397
|
+
does: tests play every test content on both, frame by frame (see
|
|
398
|
+
[How correctness is checked](#how-correctness-is-checked)).
|
|
399
|
+
|
|
400
|
+
## Versions
|
|
401
|
+
|
|
402
|
+
Runtime content records the version of this package that generated it, and the player checks it when the
|
|
403
|
+
content is loaded (`loadContentAsync`):
|
|
404
|
+
|
|
405
|
+
| Runtime content generated by | What the player does |
|
|
406
|
+
|---|---|
|
|
407
|
+
| A version in `RUNTIME_CONTENT_RANGE`, not newer than the player | Plays it |
|
|
408
|
+
| A version in `RUNTIME_CONTENT_RANGE`, newer than the player | Plays it and warns on the console: what the newer version added may not play. Update the player |
|
|
409
|
+
| A version outside `RUNTIME_CONTENT_RANGE` (or none) | Fails to load (the promise is rejected). The message says whether to update the player or to generate the runtime content again |
|
|
410
|
+
|
|
411
|
+
The generator checks the same way the definitions it is given: a definition records the version of
|
|
412
|
+
`@tawaship/animate-data-converter` that extracted it. One from a version outside the range this package
|
|
413
|
+
depends on is refused, and one from a version newer than the generator was built with is generated with a
|
|
414
|
+
warning (in `generated.warnings`; the command line tool prints it and still writes the runtime content).
|
|
415
|
+
This matters when definitions are kept as files (`animate-data-converter --out`) and generated later.
|
|
416
|
+
|
|
417
|
+
`VERSION` is the version of the player, and `satisfies(version, range)` tests a version against a range
|
|
418
|
+
written as npm writes it (`0.x || 1.x`, `^1.2.0`, `>=1.0.0 <2.0.0`).
|
|
419
|
+
|
|
420
|
+
## Claude Code skills
|
|
421
|
+
|
|
422
|
+
The package comes with skills for Claude Code (Anthropic's AI coding tool) in `dist-skills/`: `pixi-animate-runtime-guide`, which tells it how to generate runtime content and play it, and `animate-data-converter-guide` (the converter the generator runs). To
|
|
423
|
+
let Claude Code use them in your project, copy them into the project's `.claude/skills/`:
|
|
424
|
+
|
|
425
|
+
```
|
|
426
|
+
mkdir -p .claude/skills
|
|
427
|
+
cp -r node_modules/@tawaship/pixi-animate-runtime/dist-skills/* .claude/skills/
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
Copy them again after updating the package. Each skill names the versions it was written for; with another
|
|
431
|
+
version, it tells Claude Code to follow the type definitions in `node_modules` where they disagree.
|
|
432
|
+
|
|
433
|
+
## How correctness is checked
|
|
434
|
+
|
|
435
|
+
The player was developed with Claude (Anthropic's AI assistant). Its correctness rests on testing rather
|
|
436
|
+
than on trust in the author: every test content is played both by CreateJS and by this player, and their
|
|
437
|
+
states are compared at every frame (positions, playback, display lists, drawing commands, text, filters,
|
|
438
|
+
masks, buttons), together with what the PixiJS nodes show (their matrices, masks, filters, textures).
|
|
439
|
+
What is drawn is compared too: every test content is drawn by CreateJS and by this player in the same
|
|
440
|
+
headless browser, frame by frame, and the pixels are compared, with differences in antialiasing allowed for.
|
|
441
|
+
Known faults are put into the player on purpose to confirm that the comparisons notice them.
|
|
442
|
+
|
|
443
|
+
## Change log
|
|
444
|
+
|
|
445
|
+
### 0.1.1
|
|
446
|
+
|
|
447
|
+
- A `speed` below `0` stops the playing as `0` does. It kept the playing stopped for a while after the speed was
|
|
448
|
+
set above `0` again (for as long as it had been below `0`)
|
|
449
|
+
- Right after a goto made outside the playing (from a pointer event, for example), PixiJS drew synched and single
|
|
450
|
+
frame clips at their old frame, and clips coming back on the display list at the frame they had when they left,
|
|
451
|
+
until the content played its next frame (up to a frame of the content: about 0.1 s at 10 fps). They now show
|
|
452
|
+
what CreateJS shows from the first draw after the goto
|
|
453
|
+
|
|
454
|
+
### 0.1.0
|
|
455
|
+
|
|
456
|
+
- First release: generates runtime content from content published by Adobe Animate for HTML5 Canvas (the command
|
|
457
|
+
line tool and the API), and plays it on PixiJS 5.3 without CreateJS (`loadContentAsync`, `AnimateContainer`,
|
|
458
|
+
`AnimateController`, with `speed`, `overSpeed` and `smooth`)
|
|
459
|
+
- Claude Code skills in `dist-skills/`, published with the package
|
|
460
|
+
|
|
461
|
+
## License
|
|
462
|
+
|
|
463
|
+
MIT
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var readline = require('readline');
|
|
5
|
+
var generator = require('../dist/generator.cjs.js');
|
|
6
|
+
|
|
7
|
+
// Questions are asked only in a terminal: run from a script or CI, the defaults are used
|
|
8
|
+
var ask = process.stdin.isTTY ? function (question) {
|
|
9
|
+
return new Promise(function (resolve) {
|
|
10
|
+
var rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
11
|
+
rl.question(question, function (answer) {
|
|
12
|
+
rl.close();
|
|
13
|
+
resolve(answer);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
} : undefined;
|
|
17
|
+
|
|
18
|
+
generator.runCli(process.argv.slice(2), {
|
|
19
|
+
stdout: function (text) { process.stdout.write(text); },
|
|
20
|
+
stderr: function (text) { process.stderr.write(text); },
|
|
21
|
+
ask: ask
|
|
22
|
+
}).then(function (code) {
|
|
23
|
+
process.exitCode = code;
|
|
24
|
+
}, function (error) {
|
|
25
|
+
process.stderr.write((error && error.stack ? error.stack : String(error)) + '\n');
|
|
26
|
+
process.exitCode = 2;
|
|
27
|
+
});
|