@phin-tech/dottie 0.1.0 → 0.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 +19 -0
- package/dist/compile.js +391 -0
- package/dist/dottie-compile.mjs +493 -0
- package/dist/dottie-loader.js +20 -0
- package/dist/dottie-player.js +2 -2
- package/dist/dottie-player.min.js +2 -2
- package/dist/dottie.js +2 -2
- package/dist/types/cli.d.ts +1 -0
- package/dist/types/compile.d.ts +19 -0
- package/dist/types/index.d.ts +1 -1
- package/package.json +9 -2
package/README.md
CHANGED
|
@@ -36,6 +36,25 @@ The element has `play()`, `pause()`, `nextScene()`, `prevScene()`, `currentTime`
|
|
|
36
36
|
Without modules, `dist/dottie-player.min.js` is a classic script that registers the element and sets
|
|
37
37
|
`window.Dottie`.
|
|
38
38
|
|
|
39
|
+
## Compile a drawing into one script
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
npx -p @phin-tech/dottie dottie-compile tour.dottie # writes tour.js
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`tour.js` holds the player and the drawing (about 75 KB plus the drawing; around 25 KB gzipped), so one file
|
|
46
|
+
shows it anywhere you can put a script tag:
|
|
47
|
+
|
|
48
|
+
```html
|
|
49
|
+
<script src="tour.js"></script> <!-- a player right here -->
|
|
50
|
+
<script src="tour.js" data-target="#demo"></script> <!-- a player inside #demo -->
|
|
51
|
+
<script src="tour.js" data-clean data-no-loop></script> <!-- data-* set the player's attributes -->
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`dottie-compile` takes `--page`, `--at`, `--clean`, `--no-controls`, `--no-autoplay`, `--no-loop` and `--label`;
|
|
55
|
+
only the chosen page (and its pictures) goes in. The Dottie Mac app's command-line tool writes the same file:
|
|
56
|
+
`dottie render tour.dottie -f js`. From code: `import { compile } from "@phin-tech/dottie/compile"`.
|
|
57
|
+
|
|
39
58
|
## Use the library
|
|
40
59
|
|
|
41
60
|
```js
|
package/dist/compile.js
ADDED
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
/*! dottie.js 0.2.0 | Apache-2.0 | https://github.com/phin-tech/dottie */
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
|
+
|
|
6
|
+
// src/model.ts
|
|
7
|
+
var SUPPORTED_VERSION = 2;
|
|
8
|
+
var KINDS = ["rectangle", "ellipse", "diamond", "text", "connector", "freehand", "path", "note", "image"];
|
|
9
|
+
var EASES = ["linear", "easeIn", "easeOut", "easeInOut", "hold"];
|
|
10
|
+
var KNOWN_FIELDS = {
|
|
11
|
+
file: ["version", "pages", "images"],
|
|
12
|
+
page: ["id", "name", "layers", "elements", "theme", "guidesX", "guidesY", "guidesLocked", "timeline"],
|
|
13
|
+
layer: ["id", "name", "visible", "locked"],
|
|
14
|
+
rgba: ["r", "g", "b", "a"],
|
|
15
|
+
style: ["stroke", "fill", "fillStyle", "strokeWidth", "dash", "roughness", "bowing", "fontSize", "gridSize", "opacity"],
|
|
16
|
+
element: [
|
|
17
|
+
"id",
|
|
18
|
+
"kind",
|
|
19
|
+
"x",
|
|
20
|
+
"y",
|
|
21
|
+
"width",
|
|
22
|
+
"height",
|
|
23
|
+
"style",
|
|
24
|
+
"seed",
|
|
25
|
+
"layerID",
|
|
26
|
+
"text",
|
|
27
|
+
"connector",
|
|
28
|
+
"groupID",
|
|
29
|
+
"points",
|
|
30
|
+
"path",
|
|
31
|
+
"subpaths",
|
|
32
|
+
"evenOdd",
|
|
33
|
+
"rotation",
|
|
34
|
+
"link",
|
|
35
|
+
"anchor",
|
|
36
|
+
"image",
|
|
37
|
+
"reveal"
|
|
38
|
+
],
|
|
39
|
+
strokePoint: ["x", "y"],
|
|
40
|
+
subpath: ["closed", "coords"],
|
|
41
|
+
inlineImage: ["data", "format"],
|
|
42
|
+
endpoint: ["elementID", "port", "x", "y"],
|
|
43
|
+
connector: ["start", "end", "routing", "startHead", "endHead"],
|
|
44
|
+
timeline: ["fps", "duration", "boil", "settle", "poster", "tracks", "camera", "markers"],
|
|
45
|
+
track: ["element", "keys", "boil", "follow", "repeats"],
|
|
46
|
+
keyframe: ["t", "x", "y", "width", "height", "rotation", "strokeWidth", "stroke", "fill", "visible", "reveal", "opacity", "ease"],
|
|
47
|
+
follow: ["path", "start", "end", "ease", "reverse", "orient", "laps"],
|
|
48
|
+
repeat: ["start", "end", "count"],
|
|
49
|
+
cameraKey: ["t", "x", "y", "width", "height", "ease"],
|
|
50
|
+
marker: ["t", "name"]
|
|
51
|
+
};
|
|
52
|
+
var MAX_DURATION = 3600;
|
|
53
|
+
var black = { r: 0.12, g: 0.12, b: 0.13, a: 1 };
|
|
54
|
+
var clear = { r: 0, g: 0, b: 0, a: 0 };
|
|
55
|
+
var DottieFormatError = class extends Error {
|
|
56
|
+
};
|
|
57
|
+
var isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
58
|
+
var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
59
|
+
var str = (v) => typeof v === "string" ? v : void 0;
|
|
60
|
+
var bool = (v) => typeof v === "boolean" ? v : void 0;
|
|
61
|
+
var uuid = (v) => typeof v === "string" ? v.toUpperCase() : void 0;
|
|
62
|
+
function clampTime(t) {
|
|
63
|
+
if (!Number.isFinite(t)) return t === Infinity ? MAX_DURATION : 0;
|
|
64
|
+
return Math.min(Math.max(t, 0), MAX_DURATION);
|
|
65
|
+
}
|
|
66
|
+
function clampFPS(f) {
|
|
67
|
+
return Number.isFinite(f) ? Math.min(Math.max(f, 1), 60) : 12;
|
|
68
|
+
}
|
|
69
|
+
function rgba(v) {
|
|
70
|
+
if (!isObj(v)) return void 0;
|
|
71
|
+
const r = num(v.r), g = num(v.g), b = num(v.b);
|
|
72
|
+
if (r === void 0 || g === void 0 || b === void 0) return void 0;
|
|
73
|
+
return { r, g, b, a: num(v.a) ?? 1 };
|
|
74
|
+
}
|
|
75
|
+
var Reader = class {
|
|
76
|
+
constructor() {
|
|
77
|
+
__publicField(this, "warnings", []);
|
|
78
|
+
__publicField(this, "seen", /* @__PURE__ */ new Set());
|
|
79
|
+
}
|
|
80
|
+
warn(message) {
|
|
81
|
+
if (!this.seen.has(message)) {
|
|
82
|
+
this.seen.add(message);
|
|
83
|
+
this.warnings.push(message);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** Reports fields this version doesn't read (they're ignored, as Dottie ignores them). */
|
|
87
|
+
fields(v, kind) {
|
|
88
|
+
const known = KNOWN_FIELDS[kind];
|
|
89
|
+
for (const k of Object.keys(v)) if (!known.includes(k)) this.warn(`Unknown field "${k}" on ${kind}, ignored`);
|
|
90
|
+
}
|
|
91
|
+
style(v) {
|
|
92
|
+
const s = isObj(v) ? v : {};
|
|
93
|
+
this.fields(s, "style");
|
|
94
|
+
const fillStyle = str(s.fillStyle) ?? "solid";
|
|
95
|
+
const dash = str(s.dash) ?? "solid";
|
|
96
|
+
if (!["solid", "hachure", "crossHatch", "grid"].includes(fillStyle)) this.warn(`Unknown fill style "${fillStyle}", drawn solid`);
|
|
97
|
+
if (!["solid", "dashed", "dotted"].includes(dash)) this.warn(`Unknown dash "${dash}", drawn solid`);
|
|
98
|
+
return {
|
|
99
|
+
stroke: rgba(s.stroke) ?? { ...black },
|
|
100
|
+
fill: rgba(s.fill) ?? { ...clear },
|
|
101
|
+
fillStyle: ["solid", "hachure", "crossHatch", "grid"].includes(fillStyle) ? fillStyle : "solid",
|
|
102
|
+
strokeWidth: num(s.strokeWidth) ?? 2,
|
|
103
|
+
dash: ["solid", "dashed", "dotted"].includes(dash) ? dash : "solid",
|
|
104
|
+
roughness: num(s.roughness) ?? 1,
|
|
105
|
+
bowing: num(s.bowing) ?? 1,
|
|
106
|
+
fontSize: num(s.fontSize) ?? 18,
|
|
107
|
+
gridSize: num(s.gridSize) ?? null,
|
|
108
|
+
opacity: num(s.opacity) ?? null
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
endpoint(v) {
|
|
112
|
+
const e = isObj(v) ? v : {};
|
|
113
|
+
const port = str(e.port);
|
|
114
|
+
return {
|
|
115
|
+
elementID: uuid(e.elementID) ?? null,
|
|
116
|
+
port: port && ["top", "right", "bottom", "left"].includes(port) ? port : null,
|
|
117
|
+
x: num(e.x) ?? 0,
|
|
118
|
+
y: num(e.y) ?? 0
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
connector(v) {
|
|
122
|
+
if (!isObj(v)) return null;
|
|
123
|
+
this.fields(v, "connector");
|
|
124
|
+
const head = (h, d) => {
|
|
125
|
+
const s = str(h);
|
|
126
|
+
return s && ["none", "arrow", "triangle", "dot", "bar"].includes(s) ? s : d;
|
|
127
|
+
};
|
|
128
|
+
const routing = str(v.routing);
|
|
129
|
+
return {
|
|
130
|
+
start: this.endpoint(v.start),
|
|
131
|
+
end: this.endpoint(v.end),
|
|
132
|
+
routing: routing && ["straight", "curved", "elbow"].includes(routing) ? routing : "straight",
|
|
133
|
+
startHead: head(v.startHead, "none"),
|
|
134
|
+
endHead: head(v.endHead, "arrow")
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
image(v, table) {
|
|
138
|
+
if (!isObj(v)) return null;
|
|
139
|
+
const ref = str(v.ref);
|
|
140
|
+
if (ref !== void 0) return table[ref] ?? { data: "", format: "png" };
|
|
141
|
+
const data = str(v.data);
|
|
142
|
+
return data === void 0 ? null : this.picture(data, str(v.format));
|
|
143
|
+
}
|
|
144
|
+
/** A picture's bytes, only if they really are base64: they go into an attribute of the drawn SVG. */
|
|
145
|
+
picture(data, format) {
|
|
146
|
+
if (!BASE64.test(data)) {
|
|
147
|
+
this.warn("Skipped a picture whose data isn't base64");
|
|
148
|
+
return { data: "", format: "png" };
|
|
149
|
+
}
|
|
150
|
+
return { data: data.replace(/\s+/g, ""), format: format === "jpeg" ? "jpeg" : "png" };
|
|
151
|
+
}
|
|
152
|
+
element(v, images) {
|
|
153
|
+
if (!isObj(v)) return null;
|
|
154
|
+
this.fields(v, "element");
|
|
155
|
+
const id = uuid(v.id), kind = str(v.kind), layerID = uuid(v.layerID);
|
|
156
|
+
if (!id || !kind || !layerID) {
|
|
157
|
+
this.warn("Skipped an element without an id, kind or layer");
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
if (!KINDS.includes(kind)) this.warn(`Unknown element kind "${kind}", drawn as a placeholder`);
|
|
161
|
+
const subpaths = Array.isArray(v.subpaths) ? v.subpaths.filter(isObj).map((s) => ({ closed: bool(s.closed) ?? false, coords: Array.isArray(s.coords) ? s.coords.filter((c) => typeof c === "number") : [] })) : null;
|
|
162
|
+
return {
|
|
163
|
+
id,
|
|
164
|
+
kind,
|
|
165
|
+
layerID,
|
|
166
|
+
x: num(v.x) ?? 0,
|
|
167
|
+
y: num(v.y) ?? 0,
|
|
168
|
+
width: num(v.width) ?? 0,
|
|
169
|
+
height: num(v.height) ?? 0,
|
|
170
|
+
style: this.style(v.style),
|
|
171
|
+
seed: (num(v.seed) ?? 1) >>> 0,
|
|
172
|
+
text: str(v.text) ?? null,
|
|
173
|
+
connector: this.connector(v.connector),
|
|
174
|
+
groupID: uuid(v.groupID) ?? null,
|
|
175
|
+
points: Array.isArray(v.points) ? v.points.filter(isObj).map((p) => ({ x: num(p.x) ?? 0, y: num(p.y) ?? 0 })) : null,
|
|
176
|
+
path: Array.isArray(v.path) ? v.path.filter((c) => typeof c === "number") : null,
|
|
177
|
+
subpaths,
|
|
178
|
+
evenOdd: bool(v.evenOdd) ?? null,
|
|
179
|
+
rotation: num(v.rotation) ?? null,
|
|
180
|
+
link: uuid(v.link) ?? null,
|
|
181
|
+
anchor: str(v.anchor) ?? null,
|
|
182
|
+
image: this.image(v.image, images),
|
|
183
|
+
reveal: num(v.reveal) ?? null
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
ease(v) {
|
|
187
|
+
const s = str(v);
|
|
188
|
+
if (s === void 0) return null;
|
|
189
|
+
if (!EASES.includes(s)) {
|
|
190
|
+
this.warn(`Unknown ease "${s}", played linear`);
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
return s;
|
|
194
|
+
}
|
|
195
|
+
keyframe(v) {
|
|
196
|
+
if (!isObj(v)) return null;
|
|
197
|
+
this.fields(v, "keyframe");
|
|
198
|
+
const t = num(v.t);
|
|
199
|
+
if (t === void 0) return null;
|
|
200
|
+
const k = { t };
|
|
201
|
+
for (const p of ["x", "y", "width", "height", "rotation", "strokeWidth", "reveal", "opacity"]) {
|
|
202
|
+
const n = num(v[p]);
|
|
203
|
+
if (n !== void 0) k[p] = n;
|
|
204
|
+
}
|
|
205
|
+
const stroke = rgba(v.stroke), fill = rgba(v.fill), visible = bool(v.visible), ease = this.ease(v.ease);
|
|
206
|
+
if (stroke) k.stroke = stroke;
|
|
207
|
+
if (fill) k.fill = fill;
|
|
208
|
+
if (visible !== void 0) k.visible = visible;
|
|
209
|
+
if (ease) k.ease = ease;
|
|
210
|
+
return k;
|
|
211
|
+
}
|
|
212
|
+
track(v) {
|
|
213
|
+
if (!isObj(v)) return null;
|
|
214
|
+
this.fields(v, "track");
|
|
215
|
+
const element = uuid(v.element);
|
|
216
|
+
if (!element) return null;
|
|
217
|
+
const keys = (Array.isArray(v.keys) ? v.keys : []).map((k) => this.keyframe(k)).filter((k) => k !== null && k.t >= 0 && k.t <= MAX_DURATION);
|
|
218
|
+
stableSortBy(keys, (k) => k.t);
|
|
219
|
+
const follow = Array.isArray(v.follow) ? v.follow.filter(isObj).flatMap((f) => {
|
|
220
|
+
const path = uuid(f.path), start = num(f.start), end = num(f.end);
|
|
221
|
+
if (!path || start === void 0 || end === void 0 || start < 0 || end > MAX_DURATION) return [];
|
|
222
|
+
return [{ path, start, end, ease: this.ease(f.ease), reverse: bool(f.reverse) ?? null, orient: bool(f.orient) ?? null, laps: num(f.laps) ?? null }];
|
|
223
|
+
}) : null;
|
|
224
|
+
const repeats = Array.isArray(v.repeats) ? v.repeats.filter(isObj).flatMap((r) => {
|
|
225
|
+
const start = num(r.start), end = num(r.end);
|
|
226
|
+
if (start === void 0 || end === void 0) return [];
|
|
227
|
+
const count = num(r.count);
|
|
228
|
+
const rep = { start, end, count: count === void 0 ? null : Math.trunc(count) };
|
|
229
|
+
return repeatIsValid(rep) ? [rep] : [];
|
|
230
|
+
}) : null;
|
|
231
|
+
return { element, keys, boil: bool(v.boil) ?? null, follow, repeats };
|
|
232
|
+
}
|
|
233
|
+
timeline(v) {
|
|
234
|
+
if (!isObj(v)) return null;
|
|
235
|
+
this.fields(v, "timeline");
|
|
236
|
+
const boil = num(v.boil);
|
|
237
|
+
const camera = Array.isArray(v.camera) ? v.camera.filter(isObj).flatMap((c) => {
|
|
238
|
+
const t = num(c.t), x = num(c.x), y = num(c.y), width = num(c.width), height = num(c.height);
|
|
239
|
+
if (t === void 0 || x === void 0 || y === void 0 || width === void 0 || height === void 0) return [];
|
|
240
|
+
if (!(width > 1 && height > 1 && t >= 0)) return [];
|
|
241
|
+
return [{ t, x, y, width, height, ease: this.ease(c.ease) }];
|
|
242
|
+
}) : null;
|
|
243
|
+
if (camera) stableSortBy(camera, (c) => c.t);
|
|
244
|
+
const markers = Array.isArray(v.markers) ? v.markers.filter(isObj).flatMap((m) => {
|
|
245
|
+
const t = num(m.t);
|
|
246
|
+
return t !== void 0 && t >= 0 ? [{ t, name: str(m.name) ?? "" }] : [];
|
|
247
|
+
}) : null;
|
|
248
|
+
if (markers) stableSortBy(markers, (m) => m.t);
|
|
249
|
+
const poster = num(v.poster);
|
|
250
|
+
return {
|
|
251
|
+
fps: clampFPS(num(v.fps) ?? 12),
|
|
252
|
+
duration: clampTime(num(v.duration) ?? 0),
|
|
253
|
+
boil: boil !== void 0 && Number.isInteger(boil) && boil > 0 ? Math.min(boil, 1e4) : null,
|
|
254
|
+
settle: bool(v.settle) ?? null,
|
|
255
|
+
poster: poster === void 0 ? null : clampTime(poster),
|
|
256
|
+
tracks: (Array.isArray(v.tracks) ? v.tracks : []).map((t) => this.track(t)).filter((t) => t !== null),
|
|
257
|
+
camera,
|
|
258
|
+
markers
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
page(v, images, n) {
|
|
262
|
+
if (!isObj(v)) throw new DottieFormatError(`Page ${n} is not an object`);
|
|
263
|
+
this.fields(v, "page");
|
|
264
|
+
const layers = (Array.isArray(v.layers) ? v.layers : []).filter(isObj).flatMap((l) => {
|
|
265
|
+
const id = uuid(l.id);
|
|
266
|
+
return id ? [{ id, name: str(l.name) ?? "", visible: bool(l.visible) ?? true, locked: bool(l.locked) ?? false }] : [];
|
|
267
|
+
});
|
|
268
|
+
if (layers.length === 0) {
|
|
269
|
+
this.warn(`Page ${n} has no layers`);
|
|
270
|
+
layers.push({ id: "LAYER", name: "Layer 1", visible: true, locked: false });
|
|
271
|
+
}
|
|
272
|
+
return {
|
|
273
|
+
id: uuid(v.id) ?? `PAGE-${n}`,
|
|
274
|
+
name: str(v.name) ?? `Page ${n}`,
|
|
275
|
+
layers,
|
|
276
|
+
elements: (Array.isArray(v.elements) ? v.elements : []).map((e) => this.element(e, images)).filter((e) => e !== null),
|
|
277
|
+
theme: str(v.theme) ?? null,
|
|
278
|
+
timeline: this.timeline(v.timeline)
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
var BASE64 = /^[A-Za-z0-9+/=\s]*$/;
|
|
283
|
+
function repeatIsValid(r) {
|
|
284
|
+
return Number.isFinite(r.start) && Number.isFinite(r.end) && r.start >= 0 && r.end - r.start > 1e-3 && r.end <= MAX_DURATION && (r.count === null || r.count >= 1 && r.count <= 1e4);
|
|
285
|
+
}
|
|
286
|
+
function stableSortBy(a, key) {
|
|
287
|
+
const indexed = a.map((v, i) => [v, i]);
|
|
288
|
+
indexed.sort((p, q) => key(p[0]) - key(q[0]) || p[1] - q[1]);
|
|
289
|
+
for (let i = 0; i < a.length; i++) a[i] = indexed[i][0];
|
|
290
|
+
}
|
|
291
|
+
function parseDottie(source) {
|
|
292
|
+
let json = source;
|
|
293
|
+
if (typeof source === "string") {
|
|
294
|
+
try {
|
|
295
|
+
json = JSON.parse(source);
|
|
296
|
+
} catch (e) {
|
|
297
|
+
throw new DottieFormatError(`Not JSON: ${e.message}`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (!isObj(json)) throw new DottieFormatError("Not a Dottie drawing");
|
|
301
|
+
const version = num(json.version);
|
|
302
|
+
if (version === void 0) throw new DottieFormatError("Not a Dottie drawing (no version)");
|
|
303
|
+
if (!Array.isArray(json.pages) || json.pages.length === 0) throw new DottieFormatError("A drawing needs at least one page");
|
|
304
|
+
const reader = new Reader();
|
|
305
|
+
reader.fields(json, "file");
|
|
306
|
+
if (version > SUPPORTED_VERSION) reader.warn(`File version ${version} is newer than this player knows (${SUPPORTED_VERSION}); some things may not show`);
|
|
307
|
+
const images = {};
|
|
308
|
+
if (isObj(json.images)) {
|
|
309
|
+
for (const [k, v] of Object.entries(json.images)) {
|
|
310
|
+
if (isObj(v) && typeof v.data === "string") images[k] = reader.picture(v.data, str(v.format));
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
const pages = json.pages.map((p, i) => reader.page(p, images, i + 1));
|
|
314
|
+
if (new Set(pages.map((p) => p.id)).size !== pages.length) throw new DottieFormatError("Two pages share an id");
|
|
315
|
+
return { version, pages, warnings: reader.warnings };
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// src/player.ts
|
|
319
|
+
function pageIndex(file, spec) {
|
|
320
|
+
const s = (spec ?? "").trim();
|
|
321
|
+
if (!s) return 0;
|
|
322
|
+
const byName = file.pages.findIndex((p) => p.name.toLowerCase() === s.toLowerCase());
|
|
323
|
+
if (byName >= 0) return byName;
|
|
324
|
+
const n = Number(s);
|
|
325
|
+
return Number.isInteger(n) && n >= 1 && n <= file.pages.length ? n - 1 : 0;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// src/compile.ts
|
|
329
|
+
var LOADER = `;(function () {
|
|
330
|
+
var data = DOTTIE_DATA, options = DOTTIE_OPTIONS;
|
|
331
|
+
var script = document.currentScript;
|
|
332
|
+
function attr(el, name, value) { el.setAttribute(name.replace(/[A-Z]/g, function (c) { return "-" + c.toLowerCase(); }), value); }
|
|
333
|
+
function mount() {
|
|
334
|
+
var player = document.createElement("dottie-player"), k;
|
|
335
|
+
for (k in options) attr(player, k, options[k]);
|
|
336
|
+
if (script) for (k in script.dataset) if (k !== "target") attr(player, k, script.dataset[k]);
|
|
337
|
+
var target = script && script.dataset.target ? document.querySelector(script.dataset.target) : null;
|
|
338
|
+
if (target) target.appendChild(player);
|
|
339
|
+
else if (script && script.parentNode && script.parentNode !== document.head) script.parentNode.insertBefore(player, script);
|
|
340
|
+
else document.body.appendChild(player);
|
|
341
|
+
player.setFile(window.Dottie.parseDottie(data));
|
|
342
|
+
}
|
|
343
|
+
if (document.readyState === "loading" && (!script || script.parentNode === document.head || script.dataset.target)) {
|
|
344
|
+
document.addEventListener("DOMContentLoaded", mount);
|
|
345
|
+
} else {
|
|
346
|
+
mount();
|
|
347
|
+
}
|
|
348
|
+
})();
|
|
349
|
+
`;
|
|
350
|
+
function scriptJSON(value) {
|
|
351
|
+
return JSON.stringify(value).replace(/<\//g, "<\\/").replace(/<!--/g, "<\\!--").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
352
|
+
}
|
|
353
|
+
function playerAttributes(options) {
|
|
354
|
+
const out = {};
|
|
355
|
+
if (options.at !== void 0) out.at = String(options.at);
|
|
356
|
+
if (options.clean) out.clean = "";
|
|
357
|
+
if (options.noControls) out["no-controls"] = "";
|
|
358
|
+
if (options.noAutoplay) out["no-autoplay"] = "";
|
|
359
|
+
if (options.noLoop) out["no-loop"] = "";
|
|
360
|
+
if (options.label !== void 0) out.label = options.label;
|
|
361
|
+
return out;
|
|
362
|
+
}
|
|
363
|
+
function compile(source, runtime, options = {}) {
|
|
364
|
+
let raw = source;
|
|
365
|
+
if (typeof source === "string") {
|
|
366
|
+
try {
|
|
367
|
+
raw = JSON.parse(source);
|
|
368
|
+
} catch (e) {
|
|
369
|
+
throw new DottieFormatError(`Not JSON: ${e.message}`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
const file = parseDottie(raw);
|
|
373
|
+
const json = raw;
|
|
374
|
+
const i = pageIndex(file, options.page === void 0 ? null : String(options.page));
|
|
375
|
+
const page = json.pages[i];
|
|
376
|
+
const refs = /* @__PURE__ */ new Set();
|
|
377
|
+
JSON.stringify(page, (k, v) => {
|
|
378
|
+
if (k === "ref" && typeof v === "string") refs.add(v);
|
|
379
|
+
return v;
|
|
380
|
+
});
|
|
381
|
+
const images = Object.fromEntries(Object.entries(json.images ?? {}).filter(([k]) => refs.has(k)));
|
|
382
|
+
const data = { version: json.version, pages: [page] };
|
|
383
|
+
if (Object.keys(images).length) data.images = images;
|
|
384
|
+
return runtime.trimEnd() + "\n" + LOADER.replace("DOTTIE_DATA", () => scriptJSON(data)).replace("DOTTIE_OPTIONS", () => scriptJSON(playerAttributes(options)));
|
|
385
|
+
}
|
|
386
|
+
export {
|
|
387
|
+
LOADER,
|
|
388
|
+
compile,
|
|
389
|
+
playerAttributes,
|
|
390
|
+
scriptJSON
|
|
391
|
+
};
|
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/*! dottie.js 0.2.0 | Apache-2.0 | https://github.com/phin-tech/dottie */
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
6
|
+
|
|
7
|
+
// src/cli.ts
|
|
8
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
9
|
+
import { basename } from "node:path";
|
|
10
|
+
|
|
11
|
+
// src/model.ts
|
|
12
|
+
var SUPPORTED_VERSION = 2;
|
|
13
|
+
var KINDS = ["rectangle", "ellipse", "diamond", "text", "connector", "freehand", "path", "note", "image"];
|
|
14
|
+
var EASES = ["linear", "easeIn", "easeOut", "easeInOut", "hold"];
|
|
15
|
+
var KNOWN_FIELDS = {
|
|
16
|
+
file: ["version", "pages", "images"],
|
|
17
|
+
page: ["id", "name", "layers", "elements", "theme", "guidesX", "guidesY", "guidesLocked", "timeline"],
|
|
18
|
+
layer: ["id", "name", "visible", "locked"],
|
|
19
|
+
rgba: ["r", "g", "b", "a"],
|
|
20
|
+
style: ["stroke", "fill", "fillStyle", "strokeWidth", "dash", "roughness", "bowing", "fontSize", "gridSize", "opacity"],
|
|
21
|
+
element: [
|
|
22
|
+
"id",
|
|
23
|
+
"kind",
|
|
24
|
+
"x",
|
|
25
|
+
"y",
|
|
26
|
+
"width",
|
|
27
|
+
"height",
|
|
28
|
+
"style",
|
|
29
|
+
"seed",
|
|
30
|
+
"layerID",
|
|
31
|
+
"text",
|
|
32
|
+
"connector",
|
|
33
|
+
"groupID",
|
|
34
|
+
"points",
|
|
35
|
+
"path",
|
|
36
|
+
"subpaths",
|
|
37
|
+
"evenOdd",
|
|
38
|
+
"rotation",
|
|
39
|
+
"link",
|
|
40
|
+
"anchor",
|
|
41
|
+
"image",
|
|
42
|
+
"reveal"
|
|
43
|
+
],
|
|
44
|
+
strokePoint: ["x", "y"],
|
|
45
|
+
subpath: ["closed", "coords"],
|
|
46
|
+
inlineImage: ["data", "format"],
|
|
47
|
+
endpoint: ["elementID", "port", "x", "y"],
|
|
48
|
+
connector: ["start", "end", "routing", "startHead", "endHead"],
|
|
49
|
+
timeline: ["fps", "duration", "boil", "settle", "poster", "tracks", "camera", "markers"],
|
|
50
|
+
track: ["element", "keys", "boil", "follow", "repeats"],
|
|
51
|
+
keyframe: ["t", "x", "y", "width", "height", "rotation", "strokeWidth", "stroke", "fill", "visible", "reveal", "opacity", "ease"],
|
|
52
|
+
follow: ["path", "start", "end", "ease", "reverse", "orient", "laps"],
|
|
53
|
+
repeat: ["start", "end", "count"],
|
|
54
|
+
cameraKey: ["t", "x", "y", "width", "height", "ease"],
|
|
55
|
+
marker: ["t", "name"]
|
|
56
|
+
};
|
|
57
|
+
var MAX_DURATION = 3600;
|
|
58
|
+
var black = { r: 0.12, g: 0.12, b: 0.13, a: 1 };
|
|
59
|
+
var clear = { r: 0, g: 0, b: 0, a: 0 };
|
|
60
|
+
var DottieFormatError = class extends Error {
|
|
61
|
+
};
|
|
62
|
+
var isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
63
|
+
var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
64
|
+
var str = (v) => typeof v === "string" ? v : void 0;
|
|
65
|
+
var bool = (v) => typeof v === "boolean" ? v : void 0;
|
|
66
|
+
var uuid = (v) => typeof v === "string" ? v.toUpperCase() : void 0;
|
|
67
|
+
function clampTime(t) {
|
|
68
|
+
if (!Number.isFinite(t)) return t === Infinity ? MAX_DURATION : 0;
|
|
69
|
+
return Math.min(Math.max(t, 0), MAX_DURATION);
|
|
70
|
+
}
|
|
71
|
+
function clampFPS(f) {
|
|
72
|
+
return Number.isFinite(f) ? Math.min(Math.max(f, 1), 60) : 12;
|
|
73
|
+
}
|
|
74
|
+
function rgba(v) {
|
|
75
|
+
if (!isObj(v)) return void 0;
|
|
76
|
+
const r = num(v.r), g = num(v.g), b = num(v.b);
|
|
77
|
+
if (r === void 0 || g === void 0 || b === void 0) return void 0;
|
|
78
|
+
return { r, g, b, a: num(v.a) ?? 1 };
|
|
79
|
+
}
|
|
80
|
+
var Reader = class {
|
|
81
|
+
constructor() {
|
|
82
|
+
__publicField(this, "warnings", []);
|
|
83
|
+
__publicField(this, "seen", /* @__PURE__ */ new Set());
|
|
84
|
+
}
|
|
85
|
+
warn(message) {
|
|
86
|
+
if (!this.seen.has(message)) {
|
|
87
|
+
this.seen.add(message);
|
|
88
|
+
this.warnings.push(message);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/** Reports fields this version doesn't read (they're ignored, as Dottie ignores them). */
|
|
92
|
+
fields(v, kind) {
|
|
93
|
+
const known = KNOWN_FIELDS[kind];
|
|
94
|
+
for (const k of Object.keys(v)) if (!known.includes(k)) this.warn(`Unknown field "${k}" on ${kind}, ignored`);
|
|
95
|
+
}
|
|
96
|
+
style(v) {
|
|
97
|
+
const s = isObj(v) ? v : {};
|
|
98
|
+
this.fields(s, "style");
|
|
99
|
+
const fillStyle = str(s.fillStyle) ?? "solid";
|
|
100
|
+
const dash = str(s.dash) ?? "solid";
|
|
101
|
+
if (!["solid", "hachure", "crossHatch", "grid"].includes(fillStyle)) this.warn(`Unknown fill style "${fillStyle}", drawn solid`);
|
|
102
|
+
if (!["solid", "dashed", "dotted"].includes(dash)) this.warn(`Unknown dash "${dash}", drawn solid`);
|
|
103
|
+
return {
|
|
104
|
+
stroke: rgba(s.stroke) ?? { ...black },
|
|
105
|
+
fill: rgba(s.fill) ?? { ...clear },
|
|
106
|
+
fillStyle: ["solid", "hachure", "crossHatch", "grid"].includes(fillStyle) ? fillStyle : "solid",
|
|
107
|
+
strokeWidth: num(s.strokeWidth) ?? 2,
|
|
108
|
+
dash: ["solid", "dashed", "dotted"].includes(dash) ? dash : "solid",
|
|
109
|
+
roughness: num(s.roughness) ?? 1,
|
|
110
|
+
bowing: num(s.bowing) ?? 1,
|
|
111
|
+
fontSize: num(s.fontSize) ?? 18,
|
|
112
|
+
gridSize: num(s.gridSize) ?? null,
|
|
113
|
+
opacity: num(s.opacity) ?? null
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
endpoint(v) {
|
|
117
|
+
const e = isObj(v) ? v : {};
|
|
118
|
+
const port = str(e.port);
|
|
119
|
+
return {
|
|
120
|
+
elementID: uuid(e.elementID) ?? null,
|
|
121
|
+
port: port && ["top", "right", "bottom", "left"].includes(port) ? port : null,
|
|
122
|
+
x: num(e.x) ?? 0,
|
|
123
|
+
y: num(e.y) ?? 0
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
connector(v) {
|
|
127
|
+
if (!isObj(v)) return null;
|
|
128
|
+
this.fields(v, "connector");
|
|
129
|
+
const head = (h, d) => {
|
|
130
|
+
const s = str(h);
|
|
131
|
+
return s && ["none", "arrow", "triangle", "dot", "bar"].includes(s) ? s : d;
|
|
132
|
+
};
|
|
133
|
+
const routing = str(v.routing);
|
|
134
|
+
return {
|
|
135
|
+
start: this.endpoint(v.start),
|
|
136
|
+
end: this.endpoint(v.end),
|
|
137
|
+
routing: routing && ["straight", "curved", "elbow"].includes(routing) ? routing : "straight",
|
|
138
|
+
startHead: head(v.startHead, "none"),
|
|
139
|
+
endHead: head(v.endHead, "arrow")
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
image(v, table) {
|
|
143
|
+
if (!isObj(v)) return null;
|
|
144
|
+
const ref = str(v.ref);
|
|
145
|
+
if (ref !== void 0) return table[ref] ?? { data: "", format: "png" };
|
|
146
|
+
const data = str(v.data);
|
|
147
|
+
return data === void 0 ? null : this.picture(data, str(v.format));
|
|
148
|
+
}
|
|
149
|
+
/** A picture's bytes, only if they really are base64: they go into an attribute of the drawn SVG. */
|
|
150
|
+
picture(data, format) {
|
|
151
|
+
if (!BASE64.test(data)) {
|
|
152
|
+
this.warn("Skipped a picture whose data isn't base64");
|
|
153
|
+
return { data: "", format: "png" };
|
|
154
|
+
}
|
|
155
|
+
return { data: data.replace(/\s+/g, ""), format: format === "jpeg" ? "jpeg" : "png" };
|
|
156
|
+
}
|
|
157
|
+
element(v, images) {
|
|
158
|
+
if (!isObj(v)) return null;
|
|
159
|
+
this.fields(v, "element");
|
|
160
|
+
const id = uuid(v.id), kind = str(v.kind), layerID = uuid(v.layerID);
|
|
161
|
+
if (!id || !kind || !layerID) {
|
|
162
|
+
this.warn("Skipped an element without an id, kind or layer");
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
if (!KINDS.includes(kind)) this.warn(`Unknown element kind "${kind}", drawn as a placeholder`);
|
|
166
|
+
const subpaths = Array.isArray(v.subpaths) ? v.subpaths.filter(isObj).map((s) => ({ closed: bool(s.closed) ?? false, coords: Array.isArray(s.coords) ? s.coords.filter((c) => typeof c === "number") : [] })) : null;
|
|
167
|
+
return {
|
|
168
|
+
id,
|
|
169
|
+
kind,
|
|
170
|
+
layerID,
|
|
171
|
+
x: num(v.x) ?? 0,
|
|
172
|
+
y: num(v.y) ?? 0,
|
|
173
|
+
width: num(v.width) ?? 0,
|
|
174
|
+
height: num(v.height) ?? 0,
|
|
175
|
+
style: this.style(v.style),
|
|
176
|
+
seed: (num(v.seed) ?? 1) >>> 0,
|
|
177
|
+
text: str(v.text) ?? null,
|
|
178
|
+
connector: this.connector(v.connector),
|
|
179
|
+
groupID: uuid(v.groupID) ?? null,
|
|
180
|
+
points: Array.isArray(v.points) ? v.points.filter(isObj).map((p) => ({ x: num(p.x) ?? 0, y: num(p.y) ?? 0 })) : null,
|
|
181
|
+
path: Array.isArray(v.path) ? v.path.filter((c) => typeof c === "number") : null,
|
|
182
|
+
subpaths,
|
|
183
|
+
evenOdd: bool(v.evenOdd) ?? null,
|
|
184
|
+
rotation: num(v.rotation) ?? null,
|
|
185
|
+
link: uuid(v.link) ?? null,
|
|
186
|
+
anchor: str(v.anchor) ?? null,
|
|
187
|
+
image: this.image(v.image, images),
|
|
188
|
+
reveal: num(v.reveal) ?? null
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
ease(v) {
|
|
192
|
+
const s = str(v);
|
|
193
|
+
if (s === void 0) return null;
|
|
194
|
+
if (!EASES.includes(s)) {
|
|
195
|
+
this.warn(`Unknown ease "${s}", played linear`);
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
return s;
|
|
199
|
+
}
|
|
200
|
+
keyframe(v) {
|
|
201
|
+
if (!isObj(v)) return null;
|
|
202
|
+
this.fields(v, "keyframe");
|
|
203
|
+
const t = num(v.t);
|
|
204
|
+
if (t === void 0) return null;
|
|
205
|
+
const k = { t };
|
|
206
|
+
for (const p of ["x", "y", "width", "height", "rotation", "strokeWidth", "reveal", "opacity"]) {
|
|
207
|
+
const n = num(v[p]);
|
|
208
|
+
if (n !== void 0) k[p] = n;
|
|
209
|
+
}
|
|
210
|
+
const stroke = rgba(v.stroke), fill = rgba(v.fill), visible = bool(v.visible), ease = this.ease(v.ease);
|
|
211
|
+
if (stroke) k.stroke = stroke;
|
|
212
|
+
if (fill) k.fill = fill;
|
|
213
|
+
if (visible !== void 0) k.visible = visible;
|
|
214
|
+
if (ease) k.ease = ease;
|
|
215
|
+
return k;
|
|
216
|
+
}
|
|
217
|
+
track(v) {
|
|
218
|
+
if (!isObj(v)) return null;
|
|
219
|
+
this.fields(v, "track");
|
|
220
|
+
const element = uuid(v.element);
|
|
221
|
+
if (!element) return null;
|
|
222
|
+
const keys = (Array.isArray(v.keys) ? v.keys : []).map((k) => this.keyframe(k)).filter((k) => k !== null && k.t >= 0 && k.t <= MAX_DURATION);
|
|
223
|
+
stableSortBy(keys, (k) => k.t);
|
|
224
|
+
const follow = Array.isArray(v.follow) ? v.follow.filter(isObj).flatMap((f) => {
|
|
225
|
+
const path = uuid(f.path), start = num(f.start), end = num(f.end);
|
|
226
|
+
if (!path || start === void 0 || end === void 0 || start < 0 || end > MAX_DURATION) return [];
|
|
227
|
+
return [{ path, start, end, ease: this.ease(f.ease), reverse: bool(f.reverse) ?? null, orient: bool(f.orient) ?? null, laps: num(f.laps) ?? null }];
|
|
228
|
+
}) : null;
|
|
229
|
+
const repeats = Array.isArray(v.repeats) ? v.repeats.filter(isObj).flatMap((r) => {
|
|
230
|
+
const start = num(r.start), end = num(r.end);
|
|
231
|
+
if (start === void 0 || end === void 0) return [];
|
|
232
|
+
const count = num(r.count);
|
|
233
|
+
const rep = { start, end, count: count === void 0 ? null : Math.trunc(count) };
|
|
234
|
+
return repeatIsValid(rep) ? [rep] : [];
|
|
235
|
+
}) : null;
|
|
236
|
+
return { element, keys, boil: bool(v.boil) ?? null, follow, repeats };
|
|
237
|
+
}
|
|
238
|
+
timeline(v) {
|
|
239
|
+
if (!isObj(v)) return null;
|
|
240
|
+
this.fields(v, "timeline");
|
|
241
|
+
const boil = num(v.boil);
|
|
242
|
+
const camera = Array.isArray(v.camera) ? v.camera.filter(isObj).flatMap((c) => {
|
|
243
|
+
const t = num(c.t), x = num(c.x), y = num(c.y), width = num(c.width), height = num(c.height);
|
|
244
|
+
if (t === void 0 || x === void 0 || y === void 0 || width === void 0 || height === void 0) return [];
|
|
245
|
+
if (!(width > 1 && height > 1 && t >= 0)) return [];
|
|
246
|
+
return [{ t, x, y, width, height, ease: this.ease(c.ease) }];
|
|
247
|
+
}) : null;
|
|
248
|
+
if (camera) stableSortBy(camera, (c) => c.t);
|
|
249
|
+
const markers = Array.isArray(v.markers) ? v.markers.filter(isObj).flatMap((m) => {
|
|
250
|
+
const t = num(m.t);
|
|
251
|
+
return t !== void 0 && t >= 0 ? [{ t, name: str(m.name) ?? "" }] : [];
|
|
252
|
+
}) : null;
|
|
253
|
+
if (markers) stableSortBy(markers, (m) => m.t);
|
|
254
|
+
const poster = num(v.poster);
|
|
255
|
+
return {
|
|
256
|
+
fps: clampFPS(num(v.fps) ?? 12),
|
|
257
|
+
duration: clampTime(num(v.duration) ?? 0),
|
|
258
|
+
boil: boil !== void 0 && Number.isInteger(boil) && boil > 0 ? Math.min(boil, 1e4) : null,
|
|
259
|
+
settle: bool(v.settle) ?? null,
|
|
260
|
+
poster: poster === void 0 ? null : clampTime(poster),
|
|
261
|
+
tracks: (Array.isArray(v.tracks) ? v.tracks : []).map((t) => this.track(t)).filter((t) => t !== null),
|
|
262
|
+
camera,
|
|
263
|
+
markers
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
page(v, images, n) {
|
|
267
|
+
if (!isObj(v)) throw new DottieFormatError(`Page ${n} is not an object`);
|
|
268
|
+
this.fields(v, "page");
|
|
269
|
+
const layers = (Array.isArray(v.layers) ? v.layers : []).filter(isObj).flatMap((l) => {
|
|
270
|
+
const id = uuid(l.id);
|
|
271
|
+
return id ? [{ id, name: str(l.name) ?? "", visible: bool(l.visible) ?? true, locked: bool(l.locked) ?? false }] : [];
|
|
272
|
+
});
|
|
273
|
+
if (layers.length === 0) {
|
|
274
|
+
this.warn(`Page ${n} has no layers`);
|
|
275
|
+
layers.push({ id: "LAYER", name: "Layer 1", visible: true, locked: false });
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
id: uuid(v.id) ?? `PAGE-${n}`,
|
|
279
|
+
name: str(v.name) ?? `Page ${n}`,
|
|
280
|
+
layers,
|
|
281
|
+
elements: (Array.isArray(v.elements) ? v.elements : []).map((e) => this.element(e, images)).filter((e) => e !== null),
|
|
282
|
+
theme: str(v.theme) ?? null,
|
|
283
|
+
timeline: this.timeline(v.timeline)
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
var BASE64 = /^[A-Za-z0-9+/=\s]*$/;
|
|
288
|
+
function repeatIsValid(r) {
|
|
289
|
+
return Number.isFinite(r.start) && Number.isFinite(r.end) && r.start >= 0 && r.end - r.start > 1e-3 && r.end <= MAX_DURATION && (r.count === null || r.count >= 1 && r.count <= 1e4);
|
|
290
|
+
}
|
|
291
|
+
function stableSortBy(a, key) {
|
|
292
|
+
const indexed = a.map((v, i) => [v, i]);
|
|
293
|
+
indexed.sort((p, q) => key(p[0]) - key(q[0]) || p[1] - q[1]);
|
|
294
|
+
for (let i = 0; i < a.length; i++) a[i] = indexed[i][0];
|
|
295
|
+
}
|
|
296
|
+
function parseDottie(source2) {
|
|
297
|
+
let json = source2;
|
|
298
|
+
if (typeof source2 === "string") {
|
|
299
|
+
try {
|
|
300
|
+
json = JSON.parse(source2);
|
|
301
|
+
} catch (e) {
|
|
302
|
+
throw new DottieFormatError(`Not JSON: ${e.message}`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (!isObj(json)) throw new DottieFormatError("Not a Dottie drawing");
|
|
306
|
+
const version = num(json.version);
|
|
307
|
+
if (version === void 0) throw new DottieFormatError("Not a Dottie drawing (no version)");
|
|
308
|
+
if (!Array.isArray(json.pages) || json.pages.length === 0) throw new DottieFormatError("A drawing needs at least one page");
|
|
309
|
+
const reader = new Reader();
|
|
310
|
+
reader.fields(json, "file");
|
|
311
|
+
if (version > SUPPORTED_VERSION) reader.warn(`File version ${version} is newer than this player knows (${SUPPORTED_VERSION}); some things may not show`);
|
|
312
|
+
const images = {};
|
|
313
|
+
if (isObj(json.images)) {
|
|
314
|
+
for (const [k, v] of Object.entries(json.images)) {
|
|
315
|
+
if (isObj(v) && typeof v.data === "string") images[k] = reader.picture(v.data, str(v.format));
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
const pages = json.pages.map((p, i) => reader.page(p, images, i + 1));
|
|
319
|
+
if (new Set(pages.map((p) => p.id)).size !== pages.length) throw new DottieFormatError("Two pages share an id");
|
|
320
|
+
return { version, pages, warnings: reader.warnings };
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// src/player.ts
|
|
324
|
+
function pageIndex(file, spec) {
|
|
325
|
+
const s = (spec ?? "").trim();
|
|
326
|
+
if (!s) return 0;
|
|
327
|
+
const byName = file.pages.findIndex((p) => p.name.toLowerCase() === s.toLowerCase());
|
|
328
|
+
if (byName >= 0) return byName;
|
|
329
|
+
const n = Number(s);
|
|
330
|
+
return Number.isInteger(n) && n >= 1 && n <= file.pages.length ? n - 1 : 0;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// src/compile.ts
|
|
334
|
+
var LOADER = `;(function () {
|
|
335
|
+
var data = DOTTIE_DATA, options = DOTTIE_OPTIONS;
|
|
336
|
+
var script = document.currentScript;
|
|
337
|
+
function attr(el, name, value) { el.setAttribute(name.replace(/[A-Z]/g, function (c) { return "-" + c.toLowerCase(); }), value); }
|
|
338
|
+
function mount() {
|
|
339
|
+
var player = document.createElement("dottie-player"), k;
|
|
340
|
+
for (k in options) attr(player, k, options[k]);
|
|
341
|
+
if (script) for (k in script.dataset) if (k !== "target") attr(player, k, script.dataset[k]);
|
|
342
|
+
var target = script && script.dataset.target ? document.querySelector(script.dataset.target) : null;
|
|
343
|
+
if (target) target.appendChild(player);
|
|
344
|
+
else if (script && script.parentNode && script.parentNode !== document.head) script.parentNode.insertBefore(player, script);
|
|
345
|
+
else document.body.appendChild(player);
|
|
346
|
+
player.setFile(window.Dottie.parseDottie(data));
|
|
347
|
+
}
|
|
348
|
+
if (document.readyState === "loading" && (!script || script.parentNode === document.head || script.dataset.target)) {
|
|
349
|
+
document.addEventListener("DOMContentLoaded", mount);
|
|
350
|
+
} else {
|
|
351
|
+
mount();
|
|
352
|
+
}
|
|
353
|
+
})();
|
|
354
|
+
`;
|
|
355
|
+
function scriptJSON(value) {
|
|
356
|
+
return JSON.stringify(value).replace(/<\//g, "<\\/").replace(/<!--/g, "<\\!--").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
357
|
+
}
|
|
358
|
+
function playerAttributes(options2) {
|
|
359
|
+
const out = {};
|
|
360
|
+
if (options2.at !== void 0) out.at = String(options2.at);
|
|
361
|
+
if (options2.clean) out.clean = "";
|
|
362
|
+
if (options2.noControls) out["no-controls"] = "";
|
|
363
|
+
if (options2.noAutoplay) out["no-autoplay"] = "";
|
|
364
|
+
if (options2.noLoop) out["no-loop"] = "";
|
|
365
|
+
if (options2.label !== void 0) out.label = options2.label;
|
|
366
|
+
return out;
|
|
367
|
+
}
|
|
368
|
+
function compile(source2, runtime, options2 = {}) {
|
|
369
|
+
let raw = source2;
|
|
370
|
+
if (typeof source2 === "string") {
|
|
371
|
+
try {
|
|
372
|
+
raw = JSON.parse(source2);
|
|
373
|
+
} catch (e) {
|
|
374
|
+
throw new DottieFormatError(`Not JSON: ${e.message}`);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
const file = parseDottie(raw);
|
|
378
|
+
const json = raw;
|
|
379
|
+
const i = pageIndex(file, options2.page === void 0 ? null : String(options2.page));
|
|
380
|
+
const page = json.pages[i];
|
|
381
|
+
const refs = /* @__PURE__ */ new Set();
|
|
382
|
+
JSON.stringify(page, (k, v) => {
|
|
383
|
+
if (k === "ref" && typeof v === "string") refs.add(v);
|
|
384
|
+
return v;
|
|
385
|
+
});
|
|
386
|
+
const images = Object.fromEntries(Object.entries(json.images ?? {}).filter(([k]) => refs.has(k)));
|
|
387
|
+
const data = { version: json.version, pages: [page] };
|
|
388
|
+
if (Object.keys(images).length) data.images = images;
|
|
389
|
+
return runtime.trimEnd() + "\n" + LOADER.replace("DOTTIE_DATA", () => scriptJSON(data)).replace("DOTTIE_OPTIONS", () => scriptJSON(playerAttributes(options2)));
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// src/index.ts
|
|
393
|
+
var VERSION = "0.2.0";
|
|
394
|
+
|
|
395
|
+
// src/cli.ts
|
|
396
|
+
var usage = `dottie-compile ${VERSION}: a Dottie drawing as one script that plays it on any page.
|
|
397
|
+
|
|
398
|
+
USAGE
|
|
399
|
+
dottie-compile <file.dottie> [-o <out.js>] [options]
|
|
400
|
+
|
|
401
|
+
Then: <script src="drawing.js"></script> shows a player where the tag is. Add data-target="#id" to put it
|
|
402
|
+
inside another element, and data-* attributes (data-clean, data-no-loop, ...) to set the player's attributes.
|
|
403
|
+
|
|
404
|
+
OPTIONS
|
|
405
|
+
-o, --output <path> Where to write it ("-" for stdout); default drawing.js next to the input
|
|
406
|
+
-p, --page <page> Page name or 1-based number; only that page is included (default the first)
|
|
407
|
+
--at <seconds> Show that moment as a still
|
|
408
|
+
--clean Draw precisely instead of sketchy
|
|
409
|
+
--no-controls, --no-autoplay, --no-loop
|
|
410
|
+
--label <text> The player's accessible name
|
|
411
|
+
`;
|
|
412
|
+
function fail(message, code = 2) {
|
|
413
|
+
process.stderr.write(`dottie-compile: ${message}
|
|
414
|
+
`);
|
|
415
|
+
process.exit(code);
|
|
416
|
+
}
|
|
417
|
+
var args = process.argv.slice(2);
|
|
418
|
+
var options = {};
|
|
419
|
+
var input;
|
|
420
|
+
var output;
|
|
421
|
+
for (let i = 0; i < args.length; i++) {
|
|
422
|
+
const a = args[i];
|
|
423
|
+
const value = () => ++i < args.length ? args[i] : fail(`${a} needs a value`);
|
|
424
|
+
switch (a) {
|
|
425
|
+
case "-h":
|
|
426
|
+
case "--help":
|
|
427
|
+
process.stdout.write(usage);
|
|
428
|
+
process.exit(0);
|
|
429
|
+
case "-v":
|
|
430
|
+
case "--version":
|
|
431
|
+
process.stdout.write(`dottie-compile ${VERSION}
|
|
432
|
+
`);
|
|
433
|
+
process.exit(0);
|
|
434
|
+
case "-o":
|
|
435
|
+
case "--output":
|
|
436
|
+
output = value();
|
|
437
|
+
break;
|
|
438
|
+
case "-p":
|
|
439
|
+
case "--page":
|
|
440
|
+
options.page = value();
|
|
441
|
+
break;
|
|
442
|
+
case "--at": {
|
|
443
|
+
const t = Number(value());
|
|
444
|
+
if (!Number.isFinite(t) || t < 0) fail("--at must be a time in seconds");
|
|
445
|
+
options.at = t;
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
case "--clean":
|
|
449
|
+
options.clean = true;
|
|
450
|
+
break;
|
|
451
|
+
case "--no-controls":
|
|
452
|
+
options.noControls = true;
|
|
453
|
+
break;
|
|
454
|
+
case "--no-autoplay":
|
|
455
|
+
options.noAutoplay = true;
|
|
456
|
+
break;
|
|
457
|
+
case "--no-loop":
|
|
458
|
+
options.noLoop = true;
|
|
459
|
+
break;
|
|
460
|
+
case "--label":
|
|
461
|
+
options.label = value();
|
|
462
|
+
break;
|
|
463
|
+
default:
|
|
464
|
+
if (a.startsWith("-") || input) fail(`unknown option ${a}
|
|
465
|
+
|
|
466
|
+
${usage}`);
|
|
467
|
+
input = a;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (!input) fail(`needs a .dottie file
|
|
471
|
+
|
|
472
|
+
${usage}`);
|
|
473
|
+
var source;
|
|
474
|
+
try {
|
|
475
|
+
source = readFileSync(input, "utf8");
|
|
476
|
+
} catch {
|
|
477
|
+
fail(`${input}: cannot read file`, 1);
|
|
478
|
+
}
|
|
479
|
+
try {
|
|
480
|
+
for (const w of parseDottie(source).warnings) process.stderr.write(`dottie-compile: ${input}: ${w}
|
|
481
|
+
`);
|
|
482
|
+
const runtime = readFileSync(new URL("./dottie-player.min.js", import.meta.url), "utf8");
|
|
483
|
+
const js = compile(source, runtime, options);
|
|
484
|
+
if (output === "-") process.stdout.write(js);
|
|
485
|
+
else {
|
|
486
|
+
const target = output ?? input.replace(/\.dottie$/i, "") + ".js";
|
|
487
|
+
writeFileSync(target, js);
|
|
488
|
+
process.stdout.write(`${target} (${Math.round(js.length / 1024)} KB): <script src="${basename(target)}"></script>
|
|
489
|
+
`);
|
|
490
|
+
}
|
|
491
|
+
} catch (e) {
|
|
492
|
+
fail(`${input}: ${e.message}`, 1);
|
|
493
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
;(function () {
|
|
2
|
+
var data = DOTTIE_DATA, options = DOTTIE_OPTIONS;
|
|
3
|
+
var script = document.currentScript;
|
|
4
|
+
function attr(el, name, value) { el.setAttribute(name.replace(/[A-Z]/g, function (c) { return "-" + c.toLowerCase(); }), value); }
|
|
5
|
+
function mount() {
|
|
6
|
+
var player = document.createElement("dottie-player"), k;
|
|
7
|
+
for (k in options) attr(player, k, options[k]);
|
|
8
|
+
if (script) for (k in script.dataset) if (k !== "target") attr(player, k, script.dataset[k]);
|
|
9
|
+
var target = script && script.dataset.target ? document.querySelector(script.dataset.target) : null;
|
|
10
|
+
if (target) target.appendChild(player);
|
|
11
|
+
else if (script && script.parentNode && script.parentNode !== document.head) script.parentNode.insertBefore(player, script);
|
|
12
|
+
else document.body.appendChild(player);
|
|
13
|
+
player.setFile(window.Dottie.parseDottie(data));
|
|
14
|
+
}
|
|
15
|
+
if (document.readyState === "loading" && (!script || script.parentNode === document.head || script.dataset.target)) {
|
|
16
|
+
document.addEventListener("DOMContentLoaded", mount);
|
|
17
|
+
} else {
|
|
18
|
+
mount();
|
|
19
|
+
}
|
|
20
|
+
})();
|
package/dist/dottie-player.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! dottie.js 0.
|
|
1
|
+
/*! dottie.js 0.2.0 | Apache-2.0 | https://github.com/phin-tech/dottie */
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __defNormalProp = (obj, key, value2) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value: value2 }) : obj[key] = value2;
|
|
4
4
|
var __export = (target, all) => {
|
|
@@ -3022,7 +3022,7 @@ function render(source, options = {}) {
|
|
|
3022
3022
|
function isFile(v) {
|
|
3023
3023
|
return typeof v === "object" && v !== null && Array.isArray(v.pages) && Array.isArray(v.warnings);
|
|
3024
3024
|
}
|
|
3025
|
-
var VERSION = "0.
|
|
3025
|
+
var VERSION = "0.2.0";
|
|
3026
3026
|
|
|
3027
3027
|
// src/player-entry.ts
|
|
3028
3028
|
definePlayer();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! dottie.js 0.
|
|
1
|
+
/*! dottie.js 0.2.0 | Apache-2.0 | https://github.com/phin-tech/dottie */
|
|
2
2
|
"use strict";(()=>{var Oe=Object.defineProperty;var Kn=(t,e,n)=>e in t?Oe(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var Xn=(t,e)=>{for(var n in e)Oe(t,n,{get:e[n],enumerable:!0})};var b=(t,e,n)=>Kn(t,typeof e!="symbol"?e+"":e,n);var Ge={};Xn(Ge,{BOIL_DRAWINGS:()=>le,DottieFormatError:()=>q,DottiePlayer:()=>wt,KINDS:()=>Fe,KNOWN_FIELDS:()=>Ne,MAX_DURATION:()=>ht,Playback:()=>It,SUPPORTED_VERSION:()=>Zi,VERSION:()=>Xi,black:()=>ot,bounds:()=>rt,cameraView:()=>bt,clampFPS:()=>ft,clampTime:()=>dt,clear:()=>He,cloneElement:()=>_,definePlayer:()=>ne,elementIndex:()=>Jn,frameTimes:()=>Jt,inkOnDark:()=>je,inspect:()=>Un,inspectFrame:()=>ze,inspectPage:()=>Ce,isAutomaticInk:()=>ae,luminance:()=>pt,orderedElements:()=>At,pageIndex:()=>Lt,parseDottie:()=>Rt,plan:()=>kt,posterTime:()=>it,render:()=>Ui,repeatIsValid:()=>zt,resolved:()=>W,sameColor:()=>mt,sampleTimes:()=>Ye,sceneAt:()=>Hn,stableSortBy:()=>Yt,still:()=>Nn,svg:()=>ee,svgParts:()=>$t,themeNamed:()=>ut,themes:()=>Ie,transientElements:()=>jn,withRoughness:()=>Vt});var Zi=2,Fe=["rectangle","ellipse","diamond","text","connector","freehand","path","note","image"],Qn=["linear","easeIn","easeOut","easeInOut","hold"],Ne={file:["version","pages","images"],page:["id","name","layers","elements","theme","guidesX","guidesY","guidesLocked","timeline"],layer:["id","name","visible","locked"],rgba:["r","g","b","a"],style:["stroke","fill","fillStyle","strokeWidth","dash","roughness","bowing","fontSize","gridSize","opacity"],element:["id","kind","x","y","width","height","style","seed","layerID","text","connector","groupID","points","path","subpaths","evenOdd","rotation","link","anchor","image","reveal"],strokePoint:["x","y"],subpath:["closed","coords"],inlineImage:["data","format"],endpoint:["elementID","port","x","y"],connector:["start","end","routing","startHead","endHead"],timeline:["fps","duration","boil","settle","poster","tracks","camera","markers"],track:["element","keys","boil","follow","repeats"],keyframe:["t","x","y","width","height","rotation","strokeWidth","stroke","fill","visible","reveal","opacity","ease"],follow:["path","start","end","ease","reverse","orient","laps"],repeat:["start","end","count"],cameraKey:["t","x","y","width","height","ease"],marker:["t","name"]},ht=3600,le=3,ot={r:.12,g:.12,b:.13,a:1},He={r:0,g:0,b:0,a:0},je={r:.93,g:.93,b:.94,a:1},q=class extends Error{},E=t=>typeof t=="object"&&t!==null&&!Array.isArray(t),w=t=>typeof t=="number"&&Number.isFinite(t)?t:void 0,I=t=>typeof t=="string"?t:void 0,H=t=>typeof t=="boolean"?t:void 0,j=t=>typeof t=="string"?t.toUpperCase():void 0;function dt(t){return Number.isFinite(t)?Math.min(Math.max(t,0),ht):t===1/0?ht:0}function ft(t){return Number.isFinite(t)?Math.min(Math.max(t,1),60):12}function Wt(t){if(!E(t))return;let e=w(t.r),n=w(t.g),i=w(t.b);if(!(e===void 0||n===void 0||i===void 0))return{r:e,g:n,b:i,a:w(t.a)??1}}var se=class{constructor(){b(this,"warnings",[]);b(this,"seen",new Set)}warn(e){this.seen.has(e)||(this.seen.add(e),this.warnings.push(e))}fields(e,n){let i=Ne[n];for(let r of Object.keys(e))i.includes(r)||this.warn(`Unknown field "${r}" on ${n}, ignored`)}style(e){let n=E(e)?e:{};this.fields(n,"style");let i=I(n.fillStyle)??"solid",r=I(n.dash)??"solid";return["solid","hachure","crossHatch","grid"].includes(i)||this.warn(`Unknown fill style "${i}", drawn solid`),["solid","dashed","dotted"].includes(r)||this.warn(`Unknown dash "${r}", drawn solid`),{stroke:Wt(n.stroke)??{...ot},fill:Wt(n.fill)??{...He},fillStyle:["solid","hachure","crossHatch","grid"].includes(i)?i:"solid",strokeWidth:w(n.strokeWidth)??2,dash:["solid","dashed","dotted"].includes(r)?r:"solid",roughness:w(n.roughness)??1,bowing:w(n.bowing)??1,fontSize:w(n.fontSize)??18,gridSize:w(n.gridSize)??null,opacity:w(n.opacity)??null}}endpoint(e){let n=E(e)?e:{},i=I(n.port);return{elementID:j(n.elementID)??null,port:i&&["top","right","bottom","left"].includes(i)?i:null,x:w(n.x)??0,y:w(n.y)??0}}connector(e){if(!E(e))return null;this.fields(e,"connector");let n=(r,o)=>{let s=I(r);return s&&["none","arrow","triangle","dot","bar"].includes(s)?s:o},i=I(e.routing);return{start:this.endpoint(e.start),end:this.endpoint(e.end),routing:i&&["straight","curved","elbow"].includes(i)?i:"straight",startHead:n(e.startHead,"none"),endHead:n(e.endHead,"arrow")}}image(e,n){if(!E(e))return null;let i=I(e.ref);if(i!==void 0)return n[i]??{data:"",format:"png"};let r=I(e.data);return r===void 0?null:this.picture(r,I(e.format))}picture(e,n){return Zn.test(e)?{data:e.replace(/\s+/g,""),format:n==="jpeg"?"jpeg":"png"}:(this.warn("Skipped a picture whose data isn't base64"),{data:"",format:"png"})}element(e,n){if(!E(e))return null;this.fields(e,"element");let i=j(e.id),r=I(e.kind),o=j(e.layerID);if(!i||!r||!o)return this.warn("Skipped an element without an id, kind or layer"),null;Fe.includes(r)||this.warn(`Unknown element kind "${r}", drawn as a placeholder`);let s=Array.isArray(e.subpaths)?e.subpaths.filter(E).map(l=>({closed:H(l.closed)??!1,coords:Array.isArray(l.coords)?l.coords.filter(a=>typeof a=="number"):[]})):null;return{id:i,kind:r,layerID:o,x:w(e.x)??0,y:w(e.y)??0,width:w(e.width)??0,height:w(e.height)??0,style:this.style(e.style),seed:(w(e.seed)??1)>>>0,text:I(e.text)??null,connector:this.connector(e.connector),groupID:j(e.groupID)??null,points:Array.isArray(e.points)?e.points.filter(E).map(l=>({x:w(l.x)??0,y:w(l.y)??0})):null,path:Array.isArray(e.path)?e.path.filter(l=>typeof l=="number"):null,subpaths:s,evenOdd:H(e.evenOdd)??null,rotation:w(e.rotation)??null,link:j(e.link)??null,anchor:I(e.anchor)??null,image:this.image(e.image,n),reveal:w(e.reveal)??null}}ease(e){let n=I(e);return n===void 0?null:Qn.includes(n)?n:(this.warn(`Unknown ease "${n}", played linear`),null)}keyframe(e){if(!E(e))return null;this.fields(e,"keyframe");let n=w(e.t);if(n===void 0)return null;let i={t:n};for(let a of["x","y","width","height","rotation","strokeWidth","reveal","opacity"]){let c=w(e[a]);c!==void 0&&(i[a]=c)}let r=Wt(e.stroke),o=Wt(e.fill),s=H(e.visible),l=this.ease(e.ease);return r&&(i.stroke=r),o&&(i.fill=o),s!==void 0&&(i.visible=s),l&&(i.ease=l),i}track(e){if(!E(e))return null;this.fields(e,"track");let n=j(e.element);if(!n)return null;let i=(Array.isArray(e.keys)?e.keys:[]).map(s=>this.keyframe(s)).filter(s=>s!==null&&s.t>=0&&s.t<=ht);Yt(i,s=>s.t);let r=Array.isArray(e.follow)?e.follow.filter(E).flatMap(s=>{let l=j(s.path),a=w(s.start),c=w(s.end);return!l||a===void 0||c===void 0||a<0||c>ht?[]:[{path:l,start:a,end:c,ease:this.ease(s.ease),reverse:H(s.reverse)??null,orient:H(s.orient)??null,laps:w(s.laps)??null}]}):null,o=Array.isArray(e.repeats)?e.repeats.filter(E).flatMap(s=>{let l=w(s.start),a=w(s.end);if(l===void 0||a===void 0)return[];let c=w(s.count),u={start:l,end:a,count:c===void 0?null:Math.trunc(c)};return zt(u)?[u]:[]}):null;return{element:n,keys:i,boil:H(e.boil)??null,follow:r,repeats:o}}timeline(e){if(!E(e))return null;this.fields(e,"timeline");let n=w(e.boil),i=Array.isArray(e.camera)?e.camera.filter(E).flatMap(s=>{let l=w(s.t),a=w(s.x),c=w(s.y),u=w(s.width),m=w(s.height);return l===void 0||a===void 0||c===void 0||u===void 0||m===void 0?[]:u>1&&m>1&&l>=0?[{t:l,x:a,y:c,width:u,height:m,ease:this.ease(s.ease)}]:[]}):null;i&&Yt(i,s=>s.t);let r=Array.isArray(e.markers)?e.markers.filter(E).flatMap(s=>{let l=w(s.t);return l!==void 0&&l>=0?[{t:l,name:I(s.name)??""}]:[]}):null;r&&Yt(r,s=>s.t);let o=w(e.poster);return{fps:ft(w(e.fps)??12),duration:dt(w(e.duration)??0),boil:n!==void 0&&Number.isInteger(n)&&n>0?Math.min(n,1e4):null,settle:H(e.settle)??null,poster:o===void 0?null:dt(o),tracks:(Array.isArray(e.tracks)?e.tracks:[]).map(s=>this.track(s)).filter(s=>s!==null),camera:i,markers:r}}page(e,n,i){if(!E(e))throw new q(`Page ${i} is not an object`);this.fields(e,"page");let r=(Array.isArray(e.layers)?e.layers:[]).filter(E).flatMap(o=>{let s=j(o.id);return s?[{id:s,name:I(o.name)??"",visible:H(o.visible)??!0,locked:H(o.locked)??!1}]:[]});return r.length===0&&(this.warn(`Page ${i} has no layers`),r.push({id:"LAYER",name:"Layer 1",visible:!0,locked:!1})),{id:j(e.id)??`PAGE-${i}`,name:I(e.name)??`Page ${i}`,layers:r,elements:(Array.isArray(e.elements)?e.elements:[]).map(o=>this.element(o,n)).filter(o=>o!==null),theme:I(e.theme)??null,timeline:this.timeline(e.timeline)}}},Zn=/^[A-Za-z0-9+/=\s]*$/;function zt(t){return Number.isFinite(t.start)&&Number.isFinite(t.end)&&t.start>=0&&t.end-t.start>.001&&t.end<=ht&&(t.count===null||t.count>=1&&t.count<=1e4)}function Yt(t,e){let n=t.map((i,r)=>[i,r]);n.sort((i,r)=>e(i[0])-e(r[0])||i[1]-r[1]);for(let i=0;i<t.length;i++)t[i]=n[i][0]}function Rt(t){let e=t;if(typeof t=="string")try{e=JSON.parse(t)}catch(s){throw new q(`Not JSON: ${s.message}`)}if(!E(e))throw new q("Not a Dottie drawing");let n=w(e.version);if(n===void 0)throw new q("Not a Dottie drawing (no version)");if(!Array.isArray(e.pages)||e.pages.length===0)throw new q("A drawing needs at least one page");let i=new se;i.fields(e,"file"),n>2&&i.warn(`File version ${n} is newer than this player knows (2); some things may not show`);let r={};if(E(e.images))for(let[s,l]of Object.entries(e.images))E(l)&&typeof l.data=="string"&&(r[s]=i.picture(l.data,I(l.format)));let o=e.pages.map((s,l)=>i.page(s,r,l+1));if(new Set(o.map(s=>s.id)).size!==o.length)throw new q("Two pages share an id");return{version:n,pages:o,warnings:i.warnings}}function pt(t){return .2126*t.r+.7152*t.g+.0722*t.b}function mt(t,e){return t.r===e.r&&t.g===e.g&&t.b===e.b&&t.a===e.a}function ae(t){return mt(t,ot)||mt(t,je)}function _(t){return{...t,style:{...t.style,stroke:{...t.style.stroke},fill:{...t.style.fill}},connector:t.connector?{...t.connector,start:{...t.connector.start},end:{...t.connector.end}}:null}}function At(t){if(t.layers.length<=1)return t.elements;let e=new Map;t.layers.forEach((i,r)=>{e.has(i.id)||e.set(i.id,r)});let n=t.layers.map(()=>[]);for(let i of t.elements)n[e.get(i.layerID)??0].push(i);return n.flat()}function Jn(t){let e=new Map;for(let n of t.elements)e.has(n.id)||e.set(n.id,n);return e}var qe=.5522847498307936,R=class t{constructor(){b(this,"segments",[])}get isEmpty(){return this.segments.length===0}moveTo(e){return this.segments.push({op:"M",p:e}),this}lineTo(e){return this.segments.push({op:"L",p:e}),this}quadTo(e,n){return this.segments.push({op:"Q",c:n,p:e}),this}curveTo(e,n,i){return this.segments.push({op:"C",c1:n,c2:i,p:e}),this}close(){return this.segments.push({op:"Z"}),this}addPath(e){return this.segments.push(...e.segments),this}addLines(e){return e.forEach((n,i)=>i===0?this.moveTo(n):this.lineTo(n)),this}static rect(e){return new t().addLines([{x:e.x,y:e.y},{x:e.x+e.width,y:e.y},{x:e.x+e.width,y:e.y+e.height},{x:e.x,y:e.y+e.height}]).close()}addEllipse(e){let n=e.x+e.width/2,i=e.y+e.height/2,r=e.width/2,o=e.height/2,s=r*qe,l=o*qe;return this.moveTo({x:n+r,y:i}),this.curveTo({x:n,y:i+o},{x:n+r,y:i+l},{x:n+s,y:i+o}),this.curveTo({x:n-r,y:i},{x:n-s,y:i+o},{x:n-r,y:i+l}),this.curveTo({x:n,y:i-o},{x:n-r,y:i-l},{x:n-s,y:i-o}),this.curveTo({x:n+r,y:i},{x:n+s,y:i-o},{x:n+r,y:i-l}),this.close()}static ellipse(e){return new t().addEllipse(e)}translated(e,n){let i=o=>({x:o.x+e,y:o.y+n}),r=new t;return r.segments=this.segments.map(o=>{switch(o.op){case"M":case"L":return{op:o.op,p:i(o.p)};case"Q":return{op:"Q",c:i(o.c),p:i(o.p)};case"C":return{op:"C",c1:i(o.c1),c2:i(o.c2),p:i(o.p)};case"Z":return o}}),r}contours(){let e=[],n=[],i={x:0,y:0};for(let r of this.segments){let o=n.length?n[n.length-1]:i;switch(r.op){case"M":n.length>1&&e.push(n),i=r.p,n=[r.p];break;case"L":n.push(r.p);break;case"Q":for(let s=1;s<=12;s++){let l=s/12,a=1-l;n.push({x:a*a*o.x+2*a*l*r.c.x+l*l*r.p.x,y:a*a*o.y+2*a*l*r.c.y+l*l*r.p.y})}break;case"C":for(let s=1;s<=16;s++){let l=s/16,a=1-l;n.push({x:a*a*a*o.x+3*a*a*l*r.c1.x+3*a*l*l*r.c2.x+l*l*l*r.p.x,y:a*a*a*o.y+3*a*a*l*r.c1.y+3*a*l*l*r.c2.y+l*l*l*r.p.y})}break;case"Z":n.push(i),n.length>1&&e.push(n),n=[i];break}}return n.length>1&&e.push(n),e}trimmed(e){let n=this.contours().map(o=>new yt(o)),i=Math.min(Math.max(e,0),1)*n.reduce((o,s)=>o+s.length,0),r=new t;for(let o of n){if(!(i>0))break;r.moveTo(o.points[0]);for(let s=1;s<o.points.length;s++){let l=o.lengths[s]-o.lengths[s-1];if(l<=i){r.lineTo(o.points[s]),i-=l;continue}let a=o.points[s-1],c=o.points[s],u=i/l;r.lineTo({x:a.x+(c.x-a.x)*u,y:a.y+(c.y-a.y)*u}),i=0;break}}return r}data(){let e=[];for(let n of this.segments)switch(n.op){case"M":e.push(`M${y(n.p.x)} ${y(n.p.y)}`);break;case"L":e.push(`L${y(n.p.x)} ${y(n.p.y)}`);break;case"Q":e.push(`Q${y(n.c.x)} ${y(n.c.y)} ${y(n.p.x)} ${y(n.p.y)}`);break;case"C":e.push(`C${y(n.c1.x)} ${y(n.c1.y)} ${y(n.c2.x)} ${y(n.c2.y)} ${y(n.p.x)} ${y(n.p.y)}`);break;case"Z":e.push("Z");break}return e.join(" ")}};function ce(t){return t<0?-Math.round(-t):Math.round(t)}function y(t){let e=ce(t*100)/100;return Number.isInteger(e)?String(e===0?0:e):String(e)}var yt=class{constructor(e){b(this,"points");b(this,"lengths");this.points=e;let n=0;this.lengths=e.map((i,r)=>(r>0&&(n+=Math.hypot(i.x-e[r-1].x,i.y-e[r-1].y)),n))}get length(){return this.lengths.length?this.lengths[this.lengths.length-1]:0}point(e){if(this.points.length<=1||!(this.length>0))return this.points[0]??{x:0,y:0};let n=Math.min(Math.max(e,0),1)*this.length,i=1;for(;i<this.lengths.length-1&&this.lengths[i]<n;)i++;let r=this.lengths[i]-this.lengths[i-1],o=r>0?(n-this.lengths[i-1])/r:0,s=this.points[i-1],l=this.points[i];return{x:s.x+(l.x-s.x)*o,y:s.y+(l.y-s.y)*o}}},C=t=>t.x+t.width/2,G=t=>t.y+t.height/2,Y=t=>t.x+t.width,z=t=>t.y+t.height;function ue(t,e){if(!t)return{...e};let n=Math.min(t.x,e.x),i=Math.min(t.y,e.y);return{x:n,y:i,width:Math.max(Y(t),Y(e))-n,height:Math.max(z(t),z(e))-i}}function gt(t,e,n){return{x:t.x+e,y:t.y+n,width:t.width-2*e,height:t.height-2*n}}function he(t,e,n){if(n===0)return t;let i=t.x-e.x,r=t.y-e.y;return{x:e.x+i*Math.cos(n)-r*Math.sin(n),y:e.y+i*Math.sin(n)+r*Math.cos(n)}}function ti(t,e){let n=1-e;return{x:t[0].x*(n*n*n)+t[1].x*(3*e*n*n)+t[2].x*(3*e*e*n)+t[3].x*(e*e*e),y:t[0].y*(n*n*n)+t[1].y*(3*e*n*n)+t[2].y*(3*e*e*n)+t[3].y*(e*e*e)}}function _e(t,e){let n=[t[0]];for(let i=0;i<Math.floor((t.length-1)/3);i++){let r=t.slice(3*i,3*i+4),o=0;for(let l=1;l<r.length;l++)o+=Math.hypot(r[l].x-r[l-1].x,r[l].y-r[l-1].y);let s=Math.min(400,Math.max(4,Math.ceil(o/Math.max(e,.5))));for(let l=1;l<=s;l++)n.push(ti(r,l/s))}return n}var L=t=>({x:t.x,y:t.y,width:t.width,height:t.height}),O=t=>t.rotation??0,Tt=t=>({x:t.x+t.width/2,y:t.y+t.height/2}),Q=(t,e)=>he(e,Tt(t),O(t)),Ue=(t,e)=>he(e,Tt(t),-O(t));function Ke(t){let e=L(t);if(O(t)===0)return e;let n=[{x:e.x,y:e.y},{x:Y(e),y:e.y},{x:Y(e),y:z(e)},{x:e.x,y:z(e)}].map(l=>Q(t,l)),i=n.map(l=>l.x),r=n.map(l=>l.y),o=Math.min(...i),s=Math.min(...r);return{x:o,y:s,width:Math.max(...i)-o,height:Math.max(...r)-s}}function Xe(t,e){if(!ae(t.style.stroke))return t;let n=_(t),r=(t.style.fillStyle==="solid"||t.style.fillStyle==="grid")&&t.style.fill.a>=.5&&pt(t.style.fill)>.5;return n.style.stroke=pt(e)>.5&&r?{...ot}:{...e},n}function Ct(t){if(t.kind!=="path"||!t.subpaths)return[];let e=[];for(let n of t.subpaths){if(n.coords.length<8||(n.coords.length-2)%6!==0)continue;let i=[];for(let r=0;r<n.coords.length;r+=2)i.push({x:t.x+n.coords[r]*t.width,y:t.y+n.coords[r+1]*t.height});e.push({closed:n.closed,points:i})}return e}function de(t){let e=new R;for(let n of Ct(t)){e.moveTo(n.points[0]);for(let i=0;i<(n.points.length-1)/3;i++)e.curveTo(n.points[3*i+3],n.points[3*i+1],n.points[3*i+2]);n.closed&&e.close()}return e}function ei(t,e){let n=L(t),i=e==="top"?{x:C(n),y:n.y}:e==="right"?{x:Y(n),y:G(n)}:e==="bottom"?{x:C(n),y:z(n)}:{x:n.x,y:G(n)};return Q(t,i)}function ni(t,e){let n=L(t),i=Tt(t),r=Ue(t,e),o=r.x-i.x,s=r.y-i.y;if(!((o!==0||s!==0)&&n.width>0&&n.height>0))return i;let l=n.width/2,a=n.height/2,c;return t.kind==="ellipse"?c=1/Math.sqrt(o*o/(l*l)+s*s/(a*a)):t.kind==="diamond"?c=1/(Math.abs(o)/l+Math.abs(s)/a):c=Math.min(o!==0?l/Math.abs(o):1/0,s!==0?a/Math.abs(s):1/0),Q(t,{x:i.x+o*c,y:i.y+s*c})}function Qe(t,e){let n=t.elementID?e.get(t.elementID):void 0;return n?Tt(n):{x:t.x,y:t.y}}function Ze(t,e,n){let i=t.elementID?n.get(t.elementID):void 0;return i?t.port?ei(i,t.port):ni(i,e):{x:t.x,y:t.y}}function st(t,e){let n=t.connector;return n?[Ze(n.start,Qe(n.end,e),e),Ze(n.end,Qe(n.start,e),e)]:[{x:0,y:0},{x:0,y:0}]}function Z(t){if(t.kind==="polyline")return t.points;let e=[];for(let n=0;n<=24;n++){let i=n/24,r=1-i;e.push({x:r*r*r*t.a.x+3*r*r*i*t.b.x+3*r*i*i*t.c.x+i*i*i*t.d.x,y:r*r*r*t.a.y+3*r*r*i*t.b.y+3*r*i*i*t.c.y+i*i*i*t.d.y})}return e}function J(t,e){let n=t.connector;if(!n)return{kind:"polyline",points:[]};let[i,r]=st(t,e),o=r.x-i.x,s=r.y-i.y,l=Math.abs(o)>=Math.abs(s);switch(n.routing){case"straight":return{kind:"polyline",points:[i,r]};case"curved":return l?{kind:"cubic",a:i,b:{x:i.x+o/2,y:i.y},c:{x:r.x-o/2,y:r.y},d:r}:{kind:"cubic",a:i,b:{x:i.x,y:i.y+s/2},c:{x:r.x,y:r.y-s/2},d:r};case"elbow":{let a=m=>m===null?null:m==="top"||m==="bottom",c=a(n.start.port)??!l,u=a(n.end.port)??!l;if(c&&u){let m=i.y+s/2;return{kind:"polyline",points:[i,{x:i.x,y:m},{x:r.x,y:m},r]}}if(!c&&!u){let m=i.x+o/2;return{kind:"polyline",points:[i,{x:m,y:i.y},{x:m,y:r.y},r]}}return c?{kind:"polyline",points:[i,{x:i.x,y:r.y},r]}:{kind:"polyline",points:[i,{x:r.x,y:i.y},r]}}}}function Je(t,e,n){let i=Math.atan2(t.y-e.y,t.x-e.x),r=Math.PI/7,o=s=>({x:t.x-n*Math.cos(i+s),y:t.y-n*Math.sin(i+s)});return[o(r),o(-r)]}function tn(t,e){let n=Z(J(t,e));if(n.length===0)return{x:0,y:0,width:0,height:0};let i=n[0].x,r=n[0].y,o=i,s=r;for(let l of n)i=Math.min(i,l.x),r=Math.min(r,l.y),o=Math.max(o,l.x),s=Math.max(s,l.y);return{x:i,y:r,width:o-i,height:s-r}}function en(t,e){let n=Z(J(t,e));if(n.length<=1)return n[0]??{x:0,y:0};let i=[],r=0;for(let s=0;s<n.length-1;s++){let l=Math.hypot(n[s+1].x-n[s].x,n[s+1].y-n[s].y);i.push(l),r+=l}let o=r/2;for(let s=0;s<i.length;s++){let l=i[s];if(o<=l||s===i.length-1){let a=l===0?0:o/l;return{x:n[s].x+(n[s+1].x-n[s].x)*a,y:n[s].y+(n[s+1].y-n[s].y)*a}}o-=l}return n[0]}function tt(t){let e=new Map;for(let n of t.elements)e.has(n.id)||e.set(n.id,n);return e}function fe(t,e,n){let i=t[1]+n>>>0,r=i<t[1]?1:0;return[t[0]+e+r>>>0,i]}function ii(t,e){let n=t&65535,i=t>>>16,r=e&65535,o=e>>>16,s=n*r,l=n*o,a=i*r,c=i*o,u=l+a,m=s+u%65536*65536;return[c+Math.floor(u/65536)+Math.floor(m/4294967296)>>>0,m>>>0]}function pe(t,e,n){let i=ii(t[1],n);return[i[0]+Math.imul(t[0],n)+Math.imul(t[1],e)>>>0,i[1]]}function me(t,e){let n=(t[1]>>>e|t[0]<<32-e)>>>0;return[(t[0]^t[0]>>>e)>>>0,(t[1]^n)>>>0]}function nn(t){return t=pe(me(t,30),3210233709,484763065),t=pe(me(t,27),2496678331,321982955),me(t,31)}var et=class{constructor(e){b(this,"state");this.state=fe([0,e>>>0],2654435769,2135587861)}next(){return this.state=fe(this.state,2654435769,2135587861),nn(this.state)}top53(){let[e,n]=this.next();return e*2097152+(n>>>11)}signed(){return Math.floor(this.top53())/2**52-1}unit(){return this.top53()/2**53}};function rn(t,e){let n=fe([0,t>>>0],...ri(e));return n=nn(n),Math.max(1,n[1]>>>0)}function ri(t){let e=pe([0,t>>>0],2654435769,2135587861);return[e[0],e[1]]}var on=(t,e,n)=>t.signed()*e*n;function U(t,e,n,i,r,o,s){let l=Math.hypot(e.x-t.x,e.y-t.y);if(!(l>.5))return;let a=l<200?1:l>500?.4:-.0016668*l+1.233334,c=l<20?l/10:2;for(let u=0;u<2;u++){let m=(u===0?1:.5)*a,f=()=>on(n,c,i)*m,d=n.unit()*.4+.3,h=on(n,l/60,i)*r*a,p=e.x-t.x,x=e.y-t.y,M=-x/l,k=p/l,g=o?t:{x:t.x+f(),y:t.y+f()},A=o?e:{x:e.x+f(),y:e.y+f()},T=t.x+p*d*.66+M*h+f()*.5,S=t.y+x*d*.66+k*h+f()*.5,P=t.x+p*(.5+d*.5)+M*h+f()*.5,$=t.y+x*(.5+d*.5)+k*h+f()*.5;s.moveTo(g),s.curveTo(A,{x:T,y:S},{x:P,y:$})}}function ye(t,e,n,i){let r=new R;for(let o=0;o<t.length;o++)U(t[o],t[(o+1)%t.length],e,n,i,!1,r);return r}function sn(t,e,n){let i=new R,r=t.x+t.width/2,o=t.y+t.height/2,s=t.width/2,l=t.height/2;if(!(s>.5&&l>.5))return i;let a=Math.max(8,Math.min(24,Math.trunc((s+l)/6))),c=Math.min(2.5,(s+l)/25)*n;for(let u=0;u<2;u++){let m=e.unit()*2*Math.PI,f=2*Math.PI*(u===0?1:1.04),d=Math.trunc(a*f/(2*Math.PI))+1,h=[];for(let p=0;p<d;p++){let x=m+f*p/a,M=e.signed()*c,k=e.signed()*c;h.push({x:r+s*Math.cos(x)+M,y:o+l*Math.sin(x)+k})}oi(h,i)}return i}function oi(t,e){if(!(t.length<=2)){e.moveTo(t[0]);for(let n=0;n<t.length-1;n++){let i=t[Math.max(n-1,0)],r=t[n],o=t[n+1],s=t[Math.min(n+2,t.length-1)];e.curveTo(o,{x:r.x+(o.x-i.x)/6,y:r.y+(o.y-i.y)/6},{x:o.x-(s.x-r.x)/6,y:o.y-(s.y-r.y)/6})}}}var ge=-41*Math.PI/180;function ln(t,e,n){if(!(n>0))return[];let i=Math.cos(e),r=Math.sin(e),o=t.filter(f=>f.length>=3).map(f=>f.map(d=>({x:d.x*i+d.y*r,y:-d.x*r+d.y*i}))),s=o.flat();if(s.length===0)return[];let l=1/0,a=-1/0;for(let f of s)l=Math.min(l,f.y),a=Math.max(a,f.y);let c=(f,d)=>({x:f*i-d*r,y:f*r+d*i}),u=[],m=l+n/2;for(;m<a;){let f=[];for(let d of o)for(let h=0;h<d.length;h++){let p=d[h],x=d[(h+1)%d.length];(p.y<=m&&m<x.y||x.y<=m&&m<p.y)&&f.push(p.x+(m-p.y)/(x.y-p.y)*(x.x-p.x))}f.sort((d,h)=>d-h);for(let d=0;d+1<f.length;d+=2)f[d+1]-f[d]>.5&&u.push([c(f[d],m),c(f[d+1],m)]);m+=n}return u}var Gt=class{constructor(e=6e3){b(this,"map",new Map);b(this,"limit");this.limit=e}get(e,n){let i=this.map.get(e);if(i!==void 0)return i;let r=n();return this.map.size>=this.limit&&this.map.clear(),this.map.set(e,r),r}},un=new Gt,si=new Gt;function hn(t,e){let n=t.style;return[e,t.kind,t.x,t.y,t.width,t.height,t.seed,n.roughness,n.bowing,n.strokeWidth,n.fillStyle,n.fillStyle==="grid"?lt(t):0,t.path?t.path.join(","):t.subpaths?JSON.stringify(t.subpaths):""].join("|")}var lt=t=>Math.max(8,t.style.gridSize??50);function at(t){return t.kind==="freehand"&&t.path===null?cn(t):un.get(hn(t,0),()=>cn(t))}function dn(t){return[{x:t.x,y:t.y},{x:Y(t),y:t.y},{x:Y(t),y:z(t)},{x:t.x,y:z(t)}]}function Bt(t){return[{x:C(t),y:t.y},{x:Y(t),y:G(t)},{x:C(t),y:z(t)},{x:t.x,y:G(t)}]}function cn(t){let e=L(t),n=new et(t.seed),i=t.style.roughness;switch(t.kind){case"ellipse":return i<=0?R.ellipse(e):sn(e,n,i);case"diamond":return i<=0?new R().addLines(Bt(e)).close():ye(Bt(e),n,i,t.style.bowing);case"text":case"connector":return R.rect(e);case"freehand":return ai(t);case"path":return i<=0?de(t):li(t,n);default:return i<=0?R.rect(e):ye(dn(e),n,i,t.style.bowing)}}function li(t,e){let n=t.style.roughness,i=new R;for(let r of Ct(t)){let o=r.points;for(let s=0;s<(o.length-1)/3;s++){let l=o[3*s],a=o[3*s+1],c=o[3*s+2],u=o[3*s+3];if(a.x===l.x&&a.y===l.y&&c.x===u.x&&c.y===u.y){U(l,u,e,n,t.style.bowing,!0,i);continue}let m=Math.hypot(a.x-l.x,a.y-l.y)+Math.hypot(c.x-a.x,c.y-a.y)+Math.hypot(u.x-c.x,u.y-c.y),f=Math.min(2.5,m/30)*n;for(let d=0;d<2;d++){let h=d===0?1:.5,p=()=>e.signed()*f*h;i.moveTo(l);let x=a.x+p(),M=a.y+p(),k=c.x+p(),g=c.y+p();i.curveTo(u,{x,y:M},{x:k,y:g})}}}return i}function ai(t){let e=L(t),n=t.path;if(n&&n.length>=8&&(n.length-2)%6===0){let o=l=>({x:e.x+n[2*l]*e.width,y:e.y+n[2*l+1]*e.height}),s=new R().moveTo(o(0));for(let l=0;l<Math.floor((n.length/2-1)/3);l++)s.curveTo(o(3*l+3),o(3*l+1),o(3*l+2));return s}let i=(t.points??[]).map(o=>({x:e.x+o.x*e.width,y:e.y+o.y*e.height})),r=new R;if(i.length===0)return r;if(r.moveTo(i[0]),i.length===1)return r.lineTo(i[0]);if(i.length===2)return r.lineTo(i[1]);for(let o=1;o<i.length-1;o++)r.quadTo({x:(i[o].x+i[o+1].x)/2,y:(i[o].y+i[o+1].y)/2},i[o]);return r.lineTo(i[i.length-1])}function xe(t){return t.kind!=="path"?[ci(t)]:Ct(t).map(e=>_e(e.points,3))}function ci(t){let e=L(t);if(t.kind==="ellipse"){let n=[];for(let i=0;i<48;i++){let r=2*Math.PI*i/48;n.push({x:C(e)+e.width/2*Math.cos(r),y:G(e)+e.height/2*Math.sin(r)})}return n}return t.kind==="diamond"?Bt(e):dn(e)}function Ot(t){let e=L(t);return t.kind==="ellipse"?R.ellipse(e):t.kind==="path"?de(t):t.kind==="diamond"?new R().addLines(Bt(e)).close():R.rect(e)}function be(t){return t.style.fillStyle==="solid"||["freehand","connector","text","image"].includes(t.kind)?new R:un.get(hn(t,1),()=>ui(t))}function ui(t){let e=xe(t),n=new et((t.seed^1540483477)>>>0),i=new R;if(t.style.fillStyle==="grid"){for(let[s,l]of fn(e,lt(t)))t.style.roughness<=0?i.moveTo(s).lineTo(l):U(s,l,n,t.style.roughness*.3,.3,!1,i);return i}let r=Math.max(4,t.style.strokeWidth*4),o=[ge];t.style.fillStyle==="crossHatch"&&o.push(ge+Math.PI/2);for(let s of o)for(let[l,a]of ln(e,s,r))t.style.roughness<=0?i.moveTo(l).lineTo(a):U(l,a,n,t.style.roughness*.6,.5,!1,i);return i}function mn(t,e){switch(t){case"solid":return null;case"dashed":return[Math.max(8,e*4),Math.max(6,e*3)];case"dotted":return[.01,Math.max(5,e*2.6)]}}function ke(t,e){let n=t.connector;if(!n)return[new R,new R];let[i,r]=st(t,e),o=[t.seed,t.style.roughness,t.style.bowing,t.style.strokeWidth,n.routing,n.startHead,n.endHead,n.start.port,n.end.port,i.x,i.y,r.x,r.y].join("|");return si.get(o,()=>hi(t,e))}function hi(t,e){let n=t.connector,i=new et(t.seed),r=t.style.roughness,o=t.style.bowing,s=new R,l=new R,a=J(t,e);if(a.kind==="polyline"){let d=a.points;for(let h=0;h<Math.max(d.length-1,0);h++)r<=0?s.moveTo(d[h]).lineTo(d[h+1]):U(d[h],d[h+1],i,r,o,!0,s)}else{s.moveTo(a.a);let d=r*3,h=()=>i.signed()*d,p=a.b.x+h(),x=a.b.y+h(),M=a.c.x+h(),k=a.c.y+h();s.curveTo(a.d,{x:p,y:x},{x:M,y:k})}let c=Z(a),u=Math.max(10,t.style.strokeWidth*5),m=(d,h)=>{r<=0?s.moveTo(d).lineTo(h):U(d,h,i,r*.5,0,!0,s)},f=(d,h,p)=>{let[x,M]=Je(h,p,u);switch(d){case"arrow":m(x,h),m(M,h);break;case"triangle":m(x,h),m(M,h),m(x,M),l.moveTo(h).lineTo(x).lineTo(M).close();break;case"dot":{let k=u*.32,g=Math.atan2(h.y-p.y,h.x-p.x),A=h.x-k*Math.cos(g),T=h.y-k*Math.sin(g);l.addEllipse({x:A-k,y:T-k,width:2*k,height:2*k});break}case"bar":{let k=Math.atan2(h.y-p.y,h.x-p.x)+Math.PI/2,g=u*.5;m({x:h.x-g*Math.cos(k),y:h.y-g*Math.sin(k)},{x:h.x+g*Math.cos(k),y:h.y+g*Math.sin(k)});break}}};return c.length>1&&(f(n.endHead,c[c.length-1],c[c.length-2]),f(n.startHead,c[0],c[1])),[s,l]}var gn=2,we=.75,di=.8,pn=.6;function fn(t,e){return[...yn(t,e,!1),...yn(t,e,!0)]}function yn(t,e,n){if(!(e>0))return[];let i=c=>n?{x:c.y,y:c.x}:c,r=t.filter(c=>c.length>=3).map(c=>c.map(i)),o=r.flat().map(c=>c.y);if(o.length===0)return[];let s=Math.min(...o),l=Math.max(...o),a=[];for(let c=Math.floor(s/e)*e;c<l-.5;c+=e){if(!(c>s+.5))continue;let u=[];for(let m of r)for(let f=0;f<m.length;f++){let d=m[f],h=m[(f+1)%m.length];(d.y<=c&&c<h.y||h.y<=c&&c<d.y)&&u.push(d.x+(c-d.y)/(h.y-d.y)*(h.x-d.x))}u.sort((m,f)=>m-f);for(let m=0;m+1<u.length;m+=2)u[m+1]-u[m]>.5&&a.push([i({x:u[m],y:c}),i({x:u[m+1],y:c})])}return a}function xn(t){return .2126*t.r+.7152*t.g+.0722*t.b>.5?{r:t.r*.84,g:t.g*.84,b:t.b*.8,a:t.a}:{r:t.r+(1-t.r)*.25,g:t.g+(1-t.g)*.25,b:t.b+(1-t.b)*.25,a:t.a}}function Pe(t){return t.style.fillStyle==="grid"&&t.style.fill.a>0&&["rectangle","ellipse","diamond","path"].includes(t.kind)}function Nt(t,e,n){let i=(Math.imul(t,668265261)^Math.imul(e,374761393)^Math.imul(n,2654435761))>>>0;return i=Math.imul(i^i>>>15,2246822507)>>>0,i=Math.imul(i^i>>>13,3266489909)>>>0,i=(i^i>>>16)>>>0,i/4294967296}function bn(t,e,n){let i=n/gn;return{x:(t+.5+(Nt(t,e,1)-.5)*pn)*i,y:(e+.5+(Nt(t,e,2)-.5)*pn)*i}}function mi(t,e,n,i){let r=1/0;for(let o=-1;o<=1;o++)for(let s=-1;s<=1;s++){if(o===0&&s===0)continue;let l=bn(t+o,e+s,i);r=Math.min(r,Math.hypot(l.x-n.x,l.y-n.y))}return r*di}function fi(t,e,n){let i=Math.cos(e),r=Math.sin(e),o=n*.8,s=n*.5;return[-1,0,1].map(l=>{let a=t.x-r*s*l,c=t.y+i*s*l;return[{x:a-i*o,y:c-r*o},{x:a+i*o,y:c+r*o}]})}function pi(t,e){let n=!1;for(let i of t){if(i.length<3)continue;let r=i.length-1;for(let o=0;o<i.length;o++){let s=i[o],l=i[r];s.y>e.y!=l.y>e.y&&e.x<(l.x-s.x)*(e.y-s.y)/(l.y-s.y)+s.x&&(n=!n),r=o}}return n}function yi(t,e){let n=1/0;for(let i of e)if(!(i.length<2))for(let r=0;r<i.length;r++){let o=i[r],s=i[(r+1)%i.length],l=s.x-o.x,a=s.y-o.y,c=l*l+a*a,u=c>0?Math.max(0,Math.min(1,((t.x-o.x)*l+(t.y-o.y)*a)/c)):0;n=Math.min(n,Math.hypot(t.x-(o.x+u*l),t.y-(o.y+u*a)))}return n}var gi=(t,e)=>e.x>=t.x&&e.x<t.x+t.width&&e.y>=t.y&&e.y<t.y+t.height,Ft=new Map;function kn(t){if(t.length===0)return[];let e=t.map(r=>[r.kind,r.x,r.y,r.width,r.height,r.rotation??0,lt(r),JSON.stringify(r.subpaths??null),r.style.stroke.r,r.style.stroke.g,r.style.stroke.b,r.style.stroke.a,r.style.roughness,r.style.strokeWidth].join(",")).join(";"),n=Ft.get(e);if(n)return n;let i=xi(t);return Ft.size>=16&&Ft.clear(),Ft.set(e,i),i}function xi(t){let e=t.map(o=>{let s=xe(o).map(d=>d.map(h=>Q(o,h))),l=s.flat(),a=l.map(d=>d.x),c=l.map(d=>d.y),u=a.length?Math.min(...a):0,m=c.length?Math.min(...c):0,f={x:u,y:m,width:(a.length?Math.max(...a):0)-u,height:(c.length?Math.max(...c):0)-m};return{contours:s,box:f,cell:lt(o),element:o}}),n=e.map(()=>[]),i=new Set;for(let o of e){let s=o.cell/gn,l=gt(o.box,-o.cell,-o.cell),a=Math.floor(l.x/s),c=Math.ceil((l.x+l.width)/s),u=Math.floor(l.y/s),m=Math.ceil((l.y+l.height)/s),f=we*o.cell;for(let d=a;d<c;d++)for(let h=u;h<m;h++){let p=`${o.cell}|${d}|${h}`;if(i.has(p))continue;i.add(p);let x=bn(d,h,o.cell),M=1/0,k=-1;for(let S=0;S<e.length;S++){let P=e[S];if(!gi(gt(P.box,-f,-f),x))continue;if(pi(P.contours,x)){M=0;break}let $=yi(x,P.contours);$<M&&(M=$,k=S)}if(!(M>0&&M<=f&&k>=0))continue;let g=Nt(d,h,3)*Math.PI,A=mi(d,h,x,o.cell),T=Math.trunc(Nt(d,h,4)*4294967296)>>>0;for(let[S,P]of fi(x,g,A))n[k].push([S,P,T])}}let r=[];return e.forEach((o,s)=>{if(n[s].length===0)return;let l=o.element,a=new R;for(let[c,u,m]of n[s])l.style.roughness<=0?a.moveTo(c).lineTo(u):U(c,u,new et(m),l.style.roughness*.35,.2,!1,a);r.push({ink:{...l.style.stroke,a:l.style.stroke.a*.6},width:Math.max(.8,l.style.strokeWidth*.45),path:a})}),r}var Ht=.951995849609375,jt=.2129974365234375,qt=.0279998779296875,wn=.975006103515625,Pn=.2169952392578125,Mn=.0290069580078125,Rn=.957000732421875,An=.2129974365234375,Tn=.0279998779296875,vn=.975006103515625,En=.2169952392578125,Sn=.0290069580078125,$n=.60205078125,In=.92822265625,Ln=.23583984375,xt={bold:{k:{"\u2018\u2018":-95,"\u2019\u2019":-95,"\u2019s":-74,"\u2019t":-18,"A\u2019":-74,AT:-92,Av:-18,AV:-46,Aw:-18,AW:-24,Ay:-18,AY:-74,"F,":-157,"F.":-157,"f\u2019":18,FA:-55,ff:-30,fi:20,fl:20,"L\u2019":-74,LT:-92,LV:-92,LW:-55,Ly:-37,LY:-111,"P,":-179,"P.":-179,PA:-74,"r-":-55,"r,":-92,"r.":-92,rc:-18,rd:-18,re:-18,rg:-28,rn:18,ro:-18,rq:-18,RT:-18,RV:-18,RW:-18,RY:-37,"T-":-129,"T,":-111,"T;":-111,"T:":-111,"T.":-111,Ta:-111,TA:-92,Tc:-111,Te:-111,To:-111,Tr:-92,Ts:-111,Tu:-92,Tw:-111,Ty:-111,"V-":-55,"v,":-74,"V,":-129,"V;":-46,"V:":-46,"v.":-74,"V.":-129,Va:-55,VA:-46,Ve:-55,Vi:-18,Vo:-55,Vr:-37,Vu:-37,Vy:-18,"w,":-55,"W,":-74,"W;":-18,"W:":-18,"w.":-55,"W.":-74,Wa:-37,WA:-24,We:-57,Wo:-57,Wr:-18,Wu:-18,"Y-":-111,"y,":-74,"Y,":-139,"Y;":-92,"Y:":-92,"y.":-74,"Y.":-139,Ya:-92,YA:-74,Ye:-111,Yi:-37,Yo:-111,Yp:-74,Yq:-92,Yu:-74,Yv:-55},w:{" ":278,_:500,"-":407,"\u2013":500,"\u2014":1e3,",":278,";":278,":":278,"!":278,"?":556,".":278,"\u2026":1e3,"\xB7":278,"'":278,"\u2018":278,"\u2019":278,'"':463,"\u201C":463,"\u201D":463,"(":296,")":296,"[":333,"]":333,"{":333,"}":333,"@":800,"*":407,"/":371,"\\":371,"&":685,"#":556,"%":1e3,"\u2022":350,"`":259,"^":600,"\u2190":1e3,"\u2192":1e3,"\u2191":722.66,"\u2193":722.66,"+":600,"\xD7":600,"<":600,"=":600,">":600,"|":223,"~":600,"\u25E6":608.4,"\u2610":830.08,"\u2611":830.08,"\u2713":764.16,$:556,0:556,1:556,2:556,3:556,4:556,5:556,6:556,7:556,8:556,9:556,a:574,A:685,b:611,B:704,c:574,C:741,d:611,D:741,e:574,E:648,\u00E9:574,f:333,F:593,g:611,G:759,h:593,H:741,i:258,I:295,j:278,J:556,k:574,K:722,l:258,L:593,m:906,M:907,n:593,N:741,o:611,O:778,p:611,P:667,q:611,Q:778,r:389,R:722,s:537,S:649,t:352,T:611,u:593,U:741,v:520,V:630,w:814,W:944,x:537,X:667,y:519,Y:667,z:519,Z:648}},boldItalic:{k:{"\u2018\u2018":-95,"\u2019\u2019":-95,"\u2019s":-74,"\u2019t":-18,"A\u2019":-74,AT:-92,Av:-18,AV:-46,Aw:-18,AW:-24,Ay:-18,AY:-74,"F,":-157,"F.":-157,"f\u2019":18,FA:-55,ff:-68,"L\u2019":-74,LT:-92,LV:-92,LW:-55,Ly:-37,LY:-111,"P,":-179,"P.":-179,PA:-74,"r-":-55,"r,":-92,"r.":-92,rc:-18,rd:-18,re:-18,rg:-28,rn:18,ro:-18,rq:-18,RT:-18,RV:-18,RW:-18,RY:-37,"T-":-129,"T,":-111,"T;":-111,"T:":-111,"T.":-111,Ta:-111,TA:-92,Tc:-111,Te:-111,To:-111,Tr:-92,Ts:-111,Tu:-92,Tw:-111,Ty:-111,"V-":-55,"v,":-74,"V,":-129,"V;":-46,"V:":-46,"v.":-74,"V.":-129,Va:-55,VA:-46,Ve:-55,Vi:-18,Vo:-55,Vr:-37,Vu:-37,Vy:-18,"w,":-55,"W,":-74,"W;":-18,"W:":-18,"w.":-55,"W.":-74,Wa:-37,WA:-24,We:-57,Wo:-57,Wr:-18,Wu:-18,"Y-":-111,"y,":-74,"Y,":-139,"Y;":-92,"Y:":-92,"y.":-74,"Y.":-139,Ya:-92,YA:-74,Ye:-111,Yi:-37,Yo:-111,Yp:-74,Yq:-92,Yu:-74,Yv:-55},w:{" ":278,_:500,"-":407,"\u2013":500,"\u2014":1e3,",":278,";":278,":":278,"!":296,"?":574,".":278,"\u2026":1e3,"\xB7":278,"'":278,"\u2018":278,"\u2019":278,'"':481,"\u201C":481,"\u201D":481,"(":296,")":296,"[":333,"]":333,"{":333,"}":333,"@":800,"*":407,"/":389,"\\":389,"&":685,"#":556,"%":963,"\u2022":350,"`":259,"^":600,"\u2190":1e3,"\u2192":1e3,"\u2191":722.66,"\u2193":722.66,"+":600,"\xD7":600,"<":600,"=":600,">":600,"|":222,"~":600,"\u25E6":608.4,"\u2610":830.08,"\u2611":830.08,"\u2713":764.16,$:556,0:556,1:556,2:556,3:556,4:556,5:556,6:556,7:556,8:556,9:556,a:574,A:685,b:611,B:722,c:556,C:741,d:611,D:741,e:574,E:667,\u00E9:574,f:352,F:593,g:611,G:759,h:611,H:741,i:259,I:296,j:259,J:556,k:556,K:722,l:259,L:574,m:907,M:907,n:611,N:741,o:593,O:778,p:611,P:667,q:611,Q:778,r:389,R:722,s:519,S:648,t:370,T:611,u:611,U:741,v:519,V:630,w:815,W:944,x:519,X:667,y:519,Y:648,z:500,Z:648}},italic:{k:{"\u2018\u2018":-95,"\u2019\u2019":-95,"\u2019s":-74,"\u2019t":-18,"A\u2019":-74,AT:-92,Av:-18,AV:-46,Aw:-18,AW:-24,Ay:-18,AY:-74,"F,":-157,"F.":-157,"f\u2019":18,FA:-55,ff:-15,fi:1,fl:1,"L\u2019":-74,LT:-92,LV:-92,LW:-55,Ly:-37,LY:-111,"P,":-179,"P.":-179,PA:-74,"r-":-55,"r,":-92,"r.":-92,rc:-18,rd:-18,re:-18,rg:-28,rn:18,ro:-18,rq:-18,RT:-18,RV:-18,RW:-18,RY:-37,"T-":-129,"T,":-111,"T;":-111,"T:":-111,"T.":-111,Ta:-111,TA:-92,Tc:-111,Te:-111,To:-111,Tr:-92,Ts:-111,Tu:-92,Tw:-111,Ty:-111,"V-":-55,"v,":-74,"V,":-129,"V;":-46,"V:":-46,"v.":-74,"V.":-129,Va:-55,VA:-46,Ve:-55,Vi:-18,Vo:-55,Vr:-37,Vu:-37,Vy:-18,"w,":-55,"W,":-74,"W;":-18,"W:":-18,"w.":-55,"W.":-74,Wa:-37,WA:-24,We:-57,Wo:-57,Wr:-18,Wu:-18,"Y-":-111,"y,":-74,"Y,":-139,"Y;":-92,"Y:":-92,"y.":-74,"Y.":-139,Ya:-92,YA:-74,Ye:-111,Yi:-37,Yo:-111,Yp:-74,Yq:-92,Yu:-74,Yv:-55},w:{" ":278,_:500,"-":389,"\u2013":500,"\u2014":1e3,",":278,";":278,":":278,"!":259,"?":556,".":278,"\u2026":1e3,"\xB7":278,"'":278,"\u2018":278,"\u2019":278,'"':426,"\u201C":426,"\u201D":426,"(":259,")":259,"[":259,"]":259,"{":333,"}":333,"@":800,"*":352,"/":333,"\\":333,"&":630,"#":556,"%":926,"\u2022":500,"`":222,"^":600,"\u2190":1e3,"\u2192":1e3,"\u2191":645.02,"\u2193":645.02,"+":600,"\xD7":600,"<":600,"=":600,">":600,"|":222,"~":600,"\u25E6":578.13,"\u2610":830.08,"\u2611":830.08,"\u2713":764.16,$:556,0:556,1:556,2:556,3:556,4:556,5:556,6:556,7:556,8:556,9:556,a:519,A:667,b:593,B:685,c:537,C:722,d:593,D:704,e:537,E:611,\u00E9:537,f:296,F:574,g:574,G:759,h:556,H:722,i:222,I:259,j:222,J:519,k:481,K:667,l:222,L:556,m:852,M:870,n:556,N:722,o:574,O:759,p:593,P:648,q:593,Q:759,r:333,R:685,s:481,S:648,t:315,T:574,u:556,U:722,v:481,V:611,w:759,W:926,x:481,X:611,y:481,Y:611,z:444,Z:611}},regular:{k:{"\u2018\u2018":-95,"\u2019\u2019":-95,"\u2019s":-74,"\u2019t":-18,"A\u2019":-74,AT:-92,Av:-18,AV:-46,Aw:-18,AW:-24,Ay:-18,AY:-74,"F,":-157,"F.":-157,"f\u2019":18,FA:-55,ff:-15,"L\u2019":-74,LT:-92,LV:-92,LW:-55,Ly:-37,LY:-111,"P,":-179,"P.":-179,PA:-74,"r-":-55,"r,":-92,"r.":-92,rc:-18,rd:-18,re:-18,rg:-28,rn:18,ro:-18,rq:-18,RT:-18,RV:-18,RW:-18,RY:-37,"T-":-129,"T,":-111,"T;":-111,"T:":-111,"T.":-111,Ta:-111,TA:-92,Tc:-111,Te:-111,To:-111,Tr:-92,Ts:-111,Tu:-92,Tw:-111,Ty:-111,"V-":-55,"v,":-74,"V,":-129,"V;":-46,"V:":-46,"v.":-74,"V.":-129,Va:-55,VA:-46,Ve:-55,Vi:-18,Vo:-55,Vr:-37,Vu:-37,Vy:-18,"w,":-55,"W,":-74,"W;":-18,"W:":-18,"w.":-55,"W.":-74,Wa:-37,WA:-24,We:-57,Wo:-57,Wr:-18,Wu:-18,"Y-":-111,"y,":-74,"Y,":-139,"Y;":-92,"Y:":-92,"y.":-74,"Y.":-139,Ya:-92,YA:-74,Ye:-111,Yi:-37,Yo:-111,Yp:-74,Yq:-92,Yu:-74,Yv:-55},w:{" ":278,_:500,"-":389,"\u2013":500,"\u2014":1e3,",":278,";":278,":":278,"!":259,"?":556,".":278,"\u2026":1e3,"\xB7":278,"'":278,"\u2018":278,"\u2019":278,'"':426,"\u201C":426,"\u201D":426,"(":259,")":259,"[":259,"]":259,"{":333,"}":333,"@":800,"*":352,"/":333,"\\":333,"&":630,"#":556,"%":1e3,"\u2022":350,"`":222,"^":600,"\u2190":1e3,"\u2192":1e3,"\u2191":645.02,"\u2193":645.02,"+":600,"\xD7":600,"<":600,"=":600,">":600,"|":222,"~":600,"\u25E6":578.13,"\u2610":830.08,"\u2611":830.08,"\u2713":764.16,$:556,0:556,1:556,2:556,3:556,4:556,5:556,6:556,7:556,8:556,9:556,a:537,A:648,b:593,B:685,c:537,C:722,d:593,D:704,e:537,E:611,\u00E9:537,f:296,F:574,g:574,G:759,h:556,H:722,i:222,I:259,j:222,J:519,k:519,K:667,l:222,L:556,m:853,M:871,n:556,N:722,o:574,O:760,p:593,P:648,q:593,Q:760,r:333,R:685,s:500,S:648,t:315,T:574,u:556,U:722,v:500,V:611,w:758,W:926,x:518,X:611,y:500,Y:648,z:480,Z:611}}},_t={"\u2190":[.966796875,.2109375,0],"\u2192":[.966796875,.2109375,0],"\u2191":[.966796875,.2109375,0],"\u2193":[.966796875,.2109375,0],"\u25E6":[.966796875,.2109375,0],"\u2610":[.66650390625,.25,.08349609375],"\u2611":[.66650390625,.25,.08349609375],"\u2713":[.966796875,.2109375,0]};function V(t){let e=n=>Math.round(Math.min(Math.max(n,0),1)*255).toString(16).padStart(2,"0");return`#${e(t.r)}${e(t.g)}${e(t.b)}`}function Ut(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function Kt(t,e,n="regular"){let i=xt[n],r=i.w.n,o=0,s="";for(let l of t)o+=i.w[l]??r,s&&(o+=i.k[s+l]??0),s=l;return o*e/1e3}function bi(t){let e=Math.round(Ht*t),n=Math.round(jt*t),i=Math.round(qt*t);return[e+n,e+n+i]}function Me(t,e){return t===" "?!0:(t==="/"||t==="-")&&e!==""&&!/[\d\s/-]/.test(e)}function ki(t){let e=[...t],n=[],i="";return e.forEach((r,o)=>{i+=r;let s=e[o+1]??"";Me(r,s)&&s!==" "&&(n.push(i),i="")}),(i||n.length===0)&&n.push(i),n}function wi(t,e,n,i="regular"){let r=[];for(let o of t.split(/\r\n|\n|\r|\u2028|\u2029/)){let s="";for(let l of ki(o)){let a=s+l;for(s===""||Kt(a.trimEnd(),e,i)<=n?s=a:(r.push(s),s=l);Kt(s.trimEnd(),e,i)>n&&[...s.trimEnd()].length>1;){let c=[...s],u=c.length-1;for(;u>1&&Kt(c.slice(0,u).join(""),e,i)>n;)u--;r.push(c.slice(0,u).join("")),s=c.slice(u).join("")}}r.push(s)}return r}function Vn(t,e,n){if(t==="")return{width:0,height:0};let i=wi(t,e,n),r=Math.max(...i.map(l=>Kt(l.trimEnd(),e))),[o,s]=bi(e);return{width:Math.ceil(r-1e-9),height:Math.ceil(o+s*(i.length-1)-1e-9)}}var Dn=12,ct="\u2028";function Pi(t){let e=Math.min(Dn,t.width/2),n=Math.min(Dn,t.height/2);return{x:t.x+e,y:t.y+n,width:t.width-2*e,height:t.height-2*n}}var Ae=/^ {0,3}(#{1,6})(?:[ \t]+(.*?))?(?:[ \t]+#+)?[ \t]*$/,Cn=/^ {0,3}([-*_])(?:[ \t]*\1){2,}[ \t]*$/,Te=/^ {0,3}(`{3,}|~{3,})/,vt=/^( *)([-*+]|\d{1,9}[.)])([ \t]+|$)(.*)$/,Xt=/^ {0,3}> ?(.*)$/,Mi=/^ *\|? *:?-+:? *(\| *:?-+:? *)*\|? *$/;function Re(t){let e=t.trim();return e.startsWith("|")&&(e=e.slice(1)),e.endsWith("|")&&!e.endsWith("\\|")&&(e=e.slice(0,-1)),e.split(/(?<!\\)\|/).map(n=>n.trim())}function Ri(t){return $e(t.replace(/\r\n?/g,`
|
|
3
3
|
`).split(`
|
|
4
4
|
`))}function $e(t){let e=[],n=0,i=null,r=()=>{i&&(e.push({kind:"paragraph",inline:F(i.join(`
|
|
@@ -60,4 +60,4 @@ output { font-variant-numeric: tabular-nums; min-width: 4.5em; text-align: right
|
|
|
60
60
|
<button class="next" aria-label="Next scene" hidden>\u23ED</button>
|
|
61
61
|
<input class="scrub" type="range" min="0" max="0" value="0" aria-label="Frame">
|
|
62
62
|
<output class="time">0.0s</output>
|
|
63
|
-
</div>`;let n=i=>this.root.querySelector(i);this.stage=n(".stage"),this.bar=n(".bar"),this.playButton=n(".play"),this.scrub=n(".scrub"),this.time=n(".time"),this.sceneLabel=n(".scene"),this.prev=n(".prev"),this.next=n(".next"),this.playButton.onclick=()=>{let i=this.playback;i&&!this.playing&&i.scenes.length&&i.frame>=i.frameCount-1&&i.show(0),this.setPlaying(!this.playing)},this.scrub.oninput=()=>{this.setPlaying(!1),this.playback?.show(Number(this.scrub.value))},this.next.onclick=()=>this.nextScene(),this.prev.onclick=()=>this.prevScene(),this.addEventListener("keydown",i=>this.key(i))}connectedCallback(){this.hasAttribute("tabindex")||(this.tabIndex=0),"IntersectionObserver"in window&&(this.observer=new IntersectionObserver(n=>{this.visible=n.some(i=>i.isIntersecting),this.schedule()}),this.observer.observe(this)),this.load()}disconnectedCallback(){cancelAnimationFrame(this.raf),this.raf=0,this.observer?.disconnect()}attributeChangedCallback(n,i,r){i===r||!this.isConnected||(n==="src"?this.load():n==="label"?this.stage.setAttribute("aria-label",r??""):this.file&&this.mount())}async load(){let n=++this.loadToken;try{let i,r=this.getAttribute("src");if(r){let o=await fetch(r);if(!o.ok)throw new Error(`${r}: ${o.status} ${o.statusText}`);i=await o.text()}else{let o=this.querySelector('script[type="application/json"], script[type="application/vnd.dottie+json"]');if(!o)return;i=o.textContent??""}if(n!==this.loadToken)return;this.setFile(Rt(i))}catch(i){if(n!==this.loadToken)return;this.stage.innerHTML="";let r=document.createElement("div");r.className="error",r.textContent=`Couldn't show this drawing: ${i.message}`,this.stage.append(r),this.dispatchEvent(new CustomEvent("error",{detail:i}))}}setFile(n){this.file=n;for(let i of n.warnings)console.warn(`dottie-player: ${i}`);this.mount(),this.dispatchEvent(new CustomEvent("load",{detail:{file:n}}))}mount(){let n=this.file,i=n.pages[Lt(n,this.getAttribute("page"))],r=new It(i,this.stage,{clean:this.hasAttribute("clean")});this.playback=r,this.style.setProperty("--dottie-page",V(r.background)),this.style.setProperty("--dottie-ink",V(r.ink)),this.style.colorScheme=pt(r.background)<.5?"dark":"light",this.stage.setAttribute("aria-label",this.getAttribute("label")??i.name);let o=this.getAttribute("at"),s=i.timeline!==null&&r.frameCount>1&&o===null;this.bar.hidden=!s||this.hasAttribute("no-controls");let l=r.scenes.length>0;if(this.prev.hidden=this.next.hidden=this.sceneLabel.hidden=!l,this.scrub.max=String(r.frameCount-1),r.onFrame=c=>{if(this.scrub.value=String(c),this.time.textContent=`${r.plan.times[c].toFixed(1)}s`,l){let u=r.sceneAt(c);this.sceneLabel.textContent=u<0?"":r.sceneNames[u]}this.dispatchEvent(new CustomEvent("frame",{detail:{frame:c,time:r.plan.times[c]}}))},!s){r.drawAt(o!==null?Number(o)||0:it(i),o!==null?qn(r,Number(o)||0):r.posterFrame),this.setPlaying(!1);return}if(r.show(0),typeof matchMedia=="function"&&matchMedia("(prefers-reduced-motion: reduce)").matches){r.show(r.posterFrame),this.setPlaying(!1);return}this.setPlaying(!this.hasAttribute("no-autoplay")&&!r.scenes.includes(0))}get paused(){return!this.playing}get currentTime(){let n=this.playback;return n&&n.frame>=0?n.plan.times[n.frame]:0}set currentTime(n){let i=this.playback;i&&(this.setPlaying(!1),i.show(qn(i,n)))}get duration(){return this.playback?.page.timeline?.duration??0}play(){this.setPlaying(!0)}pause(){this.setPlaying(!1)}nextScene(){let n=this.playback;n&&(n.frame>=n.frameCount-1&&n.show(0),this.setPlaying(!0))}prevScene(){let n=this.playback;if(!n)return;let i=n.sceneAt(n.frame);i>=0&&n.scenes[i]===n.frame&&(i-=1),this.setPlaying(!1),n.show(i>=0?n.scenes[i]:0)}setPlaying(n){let i=this.playback;this.playing=n&&!!i&&i.frameCount>1&&i.page.timeline!==null,this.playButton.textContent=this.playing?"\u275A\u275A":"\u25B6",this.playButton.setAttribute("aria-label",this.playing?"Pause":"Play"),this.last=0,this.acc=0,this.schedule()}schedule(){this.playing&&this.visible&&!this.raf&&this.isConnected&&(this.raf=requestAnimationFrame(n=>this.tick(n)))}tick(n){this.raf=0;let i=this.playback;if(!this.playing||!i)return;let r=1e3/(i.page.timeline?.fps??12);this.last&&(this.acc+=Math.min(n-this.last,1e3)),this.last=n;let o=!1;for(;this.playing&&this.acc>=r;){this.acc-=r;let s=i.frame+1;if(s>=i.frameCount&&(i.scenes.length||this.hasAttribute("no-loop"))){this.setPlaying(!1);break}if(i.frame=s%i.frameCount,o=!0,i.scenes.includes(i.frame)){this.setPlaying(!1);break}}o&&i.show(i.frame),this.playing&&!this.visible&&(this.last=0),this.schedule()}key(n){let i=this.playback;if(!i||i.page.timeline===null||i.frameCount<=1||this.hasAttribute("at")||n.target===this.scrub&&n.key!==" ")return;let r=i.scenes.length>0,o=!0;n.key===" "?r?this.playing?this.setPlaying(!1):this.nextScene():this.setPlaying(!this.playing):n.key==="ArrowRight"?r?this.nextScene():(this.setPlaying(!1),i.show(i.frame+1)):n.key==="ArrowLeft"?r?this.prevScene():(this.setPlaying(!1),i.show(i.frame-1)):n.key==="."?(this.setPlaying(!1),i.show(i.frame+1)):n.key===","?(this.setPlaying(!1),i.show(i.frame-1)):o=!1,o&&n.preventDefault()}};b(wt,"observedAttributes",["src","page","at","clean","no-controls","label"]);function qn(t,e){let n=0;return t.plan.times.forEach((i,r)=>{Math.abs(i-e)<Math.abs(t.plan.times[n]-e)&&(n=r)}),n}function ne(t="dottie-player"){typeof customElements<"u"&&!customElements.get(t)&&customElements.define(t,class extends wt{})}var v=t=>{let e=ce(t*1e4)/1e4;return e===0?0:e},We=t=>[v(t.x),v(t.y)],Dt=t=>[v(t.x),v(t.y),v(t.width),v(t.height)],_n=t=>[v(t.r),v(t.g),v(t.b),v(t.a)];function Ye(t){let e=t.timeline;if(!e)return[0];let n=e.duration,i=[0,n];for(let r=1;r<16;r++)i.push(n*(r+.37)/16);for(let r of e.markers??[])i.push(r.t);return e.poster!==null&&i.push(e.poster),[...new Set(i.map(v))].filter(r=>r>=0&&r<=n).sort((r,o)=>r-o)}function ze(t,e){let n=W(t,e),i=tt(n),r=new Set(n.layers.filter(l=>l.visible).map(l=>l.id)),o={t:v(e)},s=t.timeline;if(s){let l=bt(s,e);o.view=l?Dt(l):null;let a=-1;(s.markers??[]).forEach((c,u)=>{c.t<=e&&(a=u)}),o.scene=a}return s?.camera?.length||(o.bounds=Dt(rt(n))),o.elements=At(n).map((l,a)=>{let c={id:l.id,kind:l.kind,z:a,seed:l.seed,frame:Dt({x:l.x,y:l.y,width:l.width,height:l.height})};if(r.has(l.layerID)||(c.hiddenLayer=!0),l.rotation!==null&&(c.rotation=v(l.rotation)),l.style.opacity!==null&&(c.opacity=v(l.style.opacity)),l.reveal!==null&&(c.reveal=v(l.reveal)),c.strokeWidth=v(l.style.strokeWidth),c.stroke=_n(l.style.stroke),c.fill=_n(l.style.fill),l.kind==="connector"){let[u,m]=st(l,i);c.start=We(u),c.end=We(m),c.route=Z(J(l,i)).map(We)}return c}),o}function Ce(t,e,n){let i={page:e+1,name:t.name,id:t.id},r=t.timeline;if(r){let o=kt(t);i.duration=v(r.duration),i.fps=v(r.fps),i.frameCount=o.times.length,i.poster=v(r.poster??r.duration),i.size=[v(o.size.width),v(o.size.height)],r.camera?.length||(i.bounds=Dt(o.rects[0])),i.markers=(r.markers??[]).map(s=>({t:v(s.t),name:s.name}))}else i.bounds=Dt(rt(t));return i.frames=n.map(o=>ze(t,o)),i}function Un(t,e){return{version:t.version,pages:t.pages.map((n,i)=>Ce(n,i,e??Ye(n)))}}function Ui(t,e={}){let n=Ki(t)?t:Rt(t),i=n.pages[Lt(n,e.page===void 0?null:String(e.page))];return i=W(i,e.at??it(i)),e.clean&&(i=Vt(i,0)),ee(i,e.background===void 0?{r:1,g:1,b:1,a:1}:e.background)}function Ki(t){return typeof t=="object"&&t!==null&&Array.isArray(t.pages)&&Array.isArray(t.warnings)}var Xi="0.
|
|
63
|
+
</div>`;let n=i=>this.root.querySelector(i);this.stage=n(".stage"),this.bar=n(".bar"),this.playButton=n(".play"),this.scrub=n(".scrub"),this.time=n(".time"),this.sceneLabel=n(".scene"),this.prev=n(".prev"),this.next=n(".next"),this.playButton.onclick=()=>{let i=this.playback;i&&!this.playing&&i.scenes.length&&i.frame>=i.frameCount-1&&i.show(0),this.setPlaying(!this.playing)},this.scrub.oninput=()=>{this.setPlaying(!1),this.playback?.show(Number(this.scrub.value))},this.next.onclick=()=>this.nextScene(),this.prev.onclick=()=>this.prevScene(),this.addEventListener("keydown",i=>this.key(i))}connectedCallback(){this.hasAttribute("tabindex")||(this.tabIndex=0),"IntersectionObserver"in window&&(this.observer=new IntersectionObserver(n=>{this.visible=n.some(i=>i.isIntersecting),this.schedule()}),this.observer.observe(this)),this.load()}disconnectedCallback(){cancelAnimationFrame(this.raf),this.raf=0,this.observer?.disconnect()}attributeChangedCallback(n,i,r){i===r||!this.isConnected||(n==="src"?this.load():n==="label"?this.stage.setAttribute("aria-label",r??""):this.file&&this.mount())}async load(){let n=++this.loadToken;try{let i,r=this.getAttribute("src");if(r){let o=await fetch(r);if(!o.ok)throw new Error(`${r}: ${o.status} ${o.statusText}`);i=await o.text()}else{let o=this.querySelector('script[type="application/json"], script[type="application/vnd.dottie+json"]');if(!o)return;i=o.textContent??""}if(n!==this.loadToken)return;this.setFile(Rt(i))}catch(i){if(n!==this.loadToken)return;this.stage.innerHTML="";let r=document.createElement("div");r.className="error",r.textContent=`Couldn't show this drawing: ${i.message}`,this.stage.append(r),this.dispatchEvent(new CustomEvent("error",{detail:i}))}}setFile(n){this.file=n;for(let i of n.warnings)console.warn(`dottie-player: ${i}`);this.mount(),this.dispatchEvent(new CustomEvent("load",{detail:{file:n}}))}mount(){let n=this.file,i=n.pages[Lt(n,this.getAttribute("page"))],r=new It(i,this.stage,{clean:this.hasAttribute("clean")});this.playback=r,this.style.setProperty("--dottie-page",V(r.background)),this.style.setProperty("--dottie-ink",V(r.ink)),this.style.colorScheme=pt(r.background)<.5?"dark":"light",this.stage.setAttribute("aria-label",this.getAttribute("label")??i.name);let o=this.getAttribute("at"),s=i.timeline!==null&&r.frameCount>1&&o===null;this.bar.hidden=!s||this.hasAttribute("no-controls");let l=r.scenes.length>0;if(this.prev.hidden=this.next.hidden=this.sceneLabel.hidden=!l,this.scrub.max=String(r.frameCount-1),r.onFrame=c=>{if(this.scrub.value=String(c),this.time.textContent=`${r.plan.times[c].toFixed(1)}s`,l){let u=r.sceneAt(c);this.sceneLabel.textContent=u<0?"":r.sceneNames[u]}this.dispatchEvent(new CustomEvent("frame",{detail:{frame:c,time:r.plan.times[c]}}))},!s){r.drawAt(o!==null?Number(o)||0:it(i),o!==null?qn(r,Number(o)||0):r.posterFrame),this.setPlaying(!1);return}if(r.show(0),typeof matchMedia=="function"&&matchMedia("(prefers-reduced-motion: reduce)").matches){r.show(r.posterFrame),this.setPlaying(!1);return}this.setPlaying(!this.hasAttribute("no-autoplay")&&!r.scenes.includes(0))}get paused(){return!this.playing}get currentTime(){let n=this.playback;return n&&n.frame>=0?n.plan.times[n.frame]:0}set currentTime(n){let i=this.playback;i&&(this.setPlaying(!1),i.show(qn(i,n)))}get duration(){return this.playback?.page.timeline?.duration??0}play(){this.setPlaying(!0)}pause(){this.setPlaying(!1)}nextScene(){let n=this.playback;n&&(n.frame>=n.frameCount-1&&n.show(0),this.setPlaying(!0))}prevScene(){let n=this.playback;if(!n)return;let i=n.sceneAt(n.frame);i>=0&&n.scenes[i]===n.frame&&(i-=1),this.setPlaying(!1),n.show(i>=0?n.scenes[i]:0)}setPlaying(n){let i=this.playback;this.playing=n&&!!i&&i.frameCount>1&&i.page.timeline!==null,this.playButton.textContent=this.playing?"\u275A\u275A":"\u25B6",this.playButton.setAttribute("aria-label",this.playing?"Pause":"Play"),this.last=0,this.acc=0,this.schedule()}schedule(){this.playing&&this.visible&&!this.raf&&this.isConnected&&(this.raf=requestAnimationFrame(n=>this.tick(n)))}tick(n){this.raf=0;let i=this.playback;if(!this.playing||!i)return;let r=1e3/(i.page.timeline?.fps??12);this.last&&(this.acc+=Math.min(n-this.last,1e3)),this.last=n;let o=!1;for(;this.playing&&this.acc>=r;){this.acc-=r;let s=i.frame+1;if(s>=i.frameCount&&(i.scenes.length||this.hasAttribute("no-loop"))){this.setPlaying(!1);break}if(i.frame=s%i.frameCount,o=!0,i.scenes.includes(i.frame)){this.setPlaying(!1);break}}o&&i.show(i.frame),this.playing&&!this.visible&&(this.last=0),this.schedule()}key(n){let i=this.playback;if(!i||i.page.timeline===null||i.frameCount<=1||this.hasAttribute("at")||n.target===this.scrub&&n.key!==" ")return;let r=i.scenes.length>0,o=!0;n.key===" "?r?this.playing?this.setPlaying(!1):this.nextScene():this.setPlaying(!this.playing):n.key==="ArrowRight"?r?this.nextScene():(this.setPlaying(!1),i.show(i.frame+1)):n.key==="ArrowLeft"?r?this.prevScene():(this.setPlaying(!1),i.show(i.frame-1)):n.key==="."?(this.setPlaying(!1),i.show(i.frame+1)):n.key===","?(this.setPlaying(!1),i.show(i.frame-1)):o=!1,o&&n.preventDefault()}};b(wt,"observedAttributes",["src","page","at","clean","no-controls","label"]);function qn(t,e){let n=0;return t.plan.times.forEach((i,r)=>{Math.abs(i-e)<Math.abs(t.plan.times[n]-e)&&(n=r)}),n}function ne(t="dottie-player"){typeof customElements<"u"&&!customElements.get(t)&&customElements.define(t,class extends wt{})}var v=t=>{let e=ce(t*1e4)/1e4;return e===0?0:e},We=t=>[v(t.x),v(t.y)],Dt=t=>[v(t.x),v(t.y),v(t.width),v(t.height)],_n=t=>[v(t.r),v(t.g),v(t.b),v(t.a)];function Ye(t){let e=t.timeline;if(!e)return[0];let n=e.duration,i=[0,n];for(let r=1;r<16;r++)i.push(n*(r+.37)/16);for(let r of e.markers??[])i.push(r.t);return e.poster!==null&&i.push(e.poster),[...new Set(i.map(v))].filter(r=>r>=0&&r<=n).sort((r,o)=>r-o)}function ze(t,e){let n=W(t,e),i=tt(n),r=new Set(n.layers.filter(l=>l.visible).map(l=>l.id)),o={t:v(e)},s=t.timeline;if(s){let l=bt(s,e);o.view=l?Dt(l):null;let a=-1;(s.markers??[]).forEach((c,u)=>{c.t<=e&&(a=u)}),o.scene=a}return s?.camera?.length||(o.bounds=Dt(rt(n))),o.elements=At(n).map((l,a)=>{let c={id:l.id,kind:l.kind,z:a,seed:l.seed,frame:Dt({x:l.x,y:l.y,width:l.width,height:l.height})};if(r.has(l.layerID)||(c.hiddenLayer=!0),l.rotation!==null&&(c.rotation=v(l.rotation)),l.style.opacity!==null&&(c.opacity=v(l.style.opacity)),l.reveal!==null&&(c.reveal=v(l.reveal)),c.strokeWidth=v(l.style.strokeWidth),c.stroke=_n(l.style.stroke),c.fill=_n(l.style.fill),l.kind==="connector"){let[u,m]=st(l,i);c.start=We(u),c.end=We(m),c.route=Z(J(l,i)).map(We)}return c}),o}function Ce(t,e,n){let i={page:e+1,name:t.name,id:t.id},r=t.timeline;if(r){let o=kt(t);i.duration=v(r.duration),i.fps=v(r.fps),i.frameCount=o.times.length,i.poster=v(r.poster??r.duration),i.size=[v(o.size.width),v(o.size.height)],r.camera?.length||(i.bounds=Dt(o.rects[0])),i.markers=(r.markers??[]).map(s=>({t:v(s.t),name:s.name}))}else i.bounds=Dt(rt(t));return i.frames=n.map(o=>ze(t,o)),i}function Un(t,e){return{version:t.version,pages:t.pages.map((n,i)=>Ce(n,i,e??Ye(n)))}}function Ui(t,e={}){let n=Ki(t)?t:Rt(t),i=n.pages[Lt(n,e.page===void 0?null:String(e.page))];return i=W(i,e.at??it(i)),e.clean&&(i=Vt(i,0)),ee(i,e.background===void 0?{r:1,g:1,b:1,a:1}:e.background)}function Ki(t){return typeof t=="object"&&t!==null&&Array.isArray(t.pages)&&Array.isArray(t.warnings)}var Xi="0.2.0";ne();globalThis.Dottie??(globalThis.Dottie=Ge);})();
|
package/dist/dottie.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! dottie.js 0.
|
|
1
|
+
/*! dottie.js 0.2.0 | Apache-2.0 | https://github.com/phin-tech/dottie */
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __defNormalProp = (obj, key, value2) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value: value2 }) : obj[key] = value2;
|
|
4
4
|
var __publicField = (obj, key, value2) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value2);
|
|
@@ -2969,7 +2969,7 @@ function render(source, options = {}) {
|
|
|
2969
2969
|
function isFile(v) {
|
|
2970
2970
|
return typeof v === "object" && v !== null && Array.isArray(v.pages) && Array.isArray(v.warnings);
|
|
2971
2971
|
}
|
|
2972
|
-
var VERSION = "0.
|
|
2972
|
+
var VERSION = "0.2.0";
|
|
2973
2973
|
export {
|
|
2974
2974
|
BOIL_DRAWINGS,
|
|
2975
2975
|
DottieFormatError,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** What follows the runtime; DOTTIE_DATA and DOTTIE_OPTIONS are replaced with JSON. Plain ES5, unminified. */
|
|
2
|
+
export declare const LOADER = ";(function () {\n var data = DOTTIE_DATA, options = DOTTIE_OPTIONS;\n var script = document.currentScript;\n function attr(el, name, value) { el.setAttribute(name.replace(/[A-Z]/g, function (c) { return \"-\" + c.toLowerCase(); }), value); }\n function mount() {\n var player = document.createElement(\"dottie-player\"), k;\n for (k in options) attr(player, k, options[k]);\n if (script) for (k in script.dataset) if (k !== \"target\") attr(player, k, script.dataset[k]);\n var target = script && script.dataset.target ? document.querySelector(script.dataset.target) : null;\n if (target) target.appendChild(player);\n else if (script && script.parentNode && script.parentNode !== document.head) script.parentNode.insertBefore(player, script);\n else document.body.appendChild(player);\n player.setFile(window.Dottie.parseDottie(data));\n }\n if (document.readyState === \"loading\" && (!script || script.parentNode === document.head || script.dataset.target)) {\n document.addEventListener(\"DOMContentLoaded\", mount);\n } else {\n mount();\n }\n})();\n";
|
|
3
|
+
export interface CompileOptions {
|
|
4
|
+
/** Page name or 1-based number; only that page goes in. The first page by default. */
|
|
5
|
+
page?: string | number;
|
|
6
|
+
/** Show this moment (seconds) as a still. */
|
|
7
|
+
at?: number;
|
|
8
|
+
clean?: boolean;
|
|
9
|
+
noControls?: boolean;
|
|
10
|
+
noAutoplay?: boolean;
|
|
11
|
+
noLoop?: boolean;
|
|
12
|
+
label?: string;
|
|
13
|
+
}
|
|
14
|
+
/** JSON safe inside a script: it can't close the tag or start a comment. */
|
|
15
|
+
export declare function scriptJSON(value: unknown): string;
|
|
16
|
+
/** The player's attributes for `options`, as both compilers write them. */
|
|
17
|
+
export declare function playerAttributes(options: CompileOptions): Record<string, string>;
|
|
18
|
+
/** The compiled script for `source` (a .dottie file's text or parsed JSON). `runtime` is dottie-player.min.js. */
|
|
19
|
+
export declare function compile(source: string | unknown, runtime: string, options?: CompileOptions): string;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -18,4 +18,4 @@ export interface RenderOptions {
|
|
|
18
18
|
/** One page of a drawing as an SVG document, as Dottie's own SVG export draws it. */
|
|
19
19
|
export declare function render(source: string | DottieFile | unknown, options?: RenderOptions): string;
|
|
20
20
|
/** The library's version. */
|
|
21
|
-
export declare const VERSION = "0.
|
|
21
|
+
export declare const VERSION = "0.2.0";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phin-tech/dottie",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Render and
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Render, play and compile Dottie (.dottie) drawings and animations in the browser",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
"./player": {
|
|
22
22
|
"types": "./dist/types/player-entry.d.ts",
|
|
23
23
|
"default": "./dist/dottie-player.js"
|
|
24
|
+
},
|
|
25
|
+
"./compile": {
|
|
26
|
+
"types": "./dist/types/compile.d.ts",
|
|
27
|
+
"default": "./dist/compile.js"
|
|
24
28
|
}
|
|
25
29
|
},
|
|
26
30
|
"files": [
|
|
@@ -64,5 +68,8 @@
|
|
|
64
68
|
],
|
|
65
69
|
"engines": {
|
|
66
70
|
"node": ">=18"
|
|
71
|
+
},
|
|
72
|
+
"bin": {
|
|
73
|
+
"dottie-compile": "dist/dottie-compile.mjs"
|
|
67
74
|
}
|
|
68
75
|
}
|