@phin-tech/dottie 0.10.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/PARITY.md CHANGED
@@ -24,6 +24,8 @@ fixture, so the gap is visible rather than silent.
24
24
  | Ports and edge-following, rotated shapes, free ends | Supported | [edge/connectors](../fixtures/edge/connectors.dottie) | |
25
25
  | Connectors and labels on outlines (ADR 0001) | Supported | [edge/extensions](../fixtures/edge/extensions.dottie) | Edge-following meets a `.path`'s actual outline, not its box (ray against 16-step flattened curves). Endpoints pinned with `portIndex` attach to the element's `ports`. A path's label goes in its `labelRect`. |
26
26
  | Extension shapes as stored (ADR 0001) | Supported | [edge/extensions](../fixtures/edge/extensions.dottie) | Drawn from the stored path with no extension installed. The `extension` field is kept as metadata and nothing runs. Parameters, commands and handles are Dottie-only. |
27
+ | Click logic (`logic`, a click's `run`) | Supported | [edge/logic](../fixtures/edge/logic.dottie) | One engine for both: `logic.ts` (QuickJS in WebAssembly), run by `LogicEngine.swift` in JavaScriptCore. Runs only with `allow-logic` (ADR 0007). |
28
+ | Number variables, expressions in conditions and clicks, `{value}` in labels | Supported | [edge/counters](../fixtures/edge/counters.dottie), [expressions.json](../fixtures/expressions.json) | One grammar in `Expression.swift` and `expression.ts` (ADR 0007). |
27
29
  | Containers and swimlanes | Supported | [edge/containers](../fixtures/edge/containers.dottie) | Drawn from the stored frame and title band (`labelRect`); the app keeps them fitted (ADR 0006). |
28
30
  | Themes of a page's own, and palette colors by name | Supported | [edge/palette](../fixtures/edge/palette.dottie) | Names are resolved when a file is read, by the same rules in `Theme.swift` and `theme.ts` (ADR 0005). |
29
31
  | Elbows that go round shapes (`avoid`) | Supported | [edge/elbow-around](../fixtures/edge/elbow-around.dottie) | The same grid router, point for point (`ElbowRouter.swift`, `elbow.ts`). |
@@ -57,6 +59,6 @@ fixture, so the gap is visible rather than silent.
57
59
  | Clicks that set and toggle variables | Supported | [edge/state](../fixtures/edge/state.dottie) | Change what shows without touching the playhead |
58
60
  | Looping scenes (`loop` on a marker) | Supported | [edge/state](../fixtures/edge/state.dottie) | No stop on entering, round from the scene's end to its start |
59
61
  | Links out of the drawing (`url`) | Supported | [edge/links](../fixtures/edge/links.dottie) | A web or mail `url` opens when clicked if there is no `click`, and SVG export wraps it in `<a>`; a link to another drawing does nothing on the web |
60
- | Links between shapes and pages | Partial | [edge/clicks](../fixtures/edge/clicks.dottie) | A link to a shape on another page shows that page; one on the same page does nothing. The HTML export holds one page, so it has neither |
62
+ | Links between shapes and pages | Partial | [edge/clicks](../fixtures/edge/clicks.dottie) | A link to a shape on another page shows that page; one on the same page does nothing. The HTML export of one page has neither; with every page (`--all-pages`, `history`) it shows the page at its own address, and split a page per file (`--split`, `links`) it goes to that page's file |
61
63
  | Editing | Missing | | |
62
64
  | Ticking task boxes in notes | Missing | | Drawn, not clickable |
package/README.md CHANGED
@@ -28,6 +28,8 @@ prefer reduced motion. A still page is just the drawing.
28
28
  | `clean` | Draw precisely instead of sketchy |
29
29
  | `no-controls`, `no-autoplay`, `no-loop` | |
30
30
  | `label` | The accessible name; the page name by default |
31
+ | `history` | Each page a link shows gets its own address (`#` and the page's name), so Back and Forward go between pages and a link can open any of them. One such player to a page |
32
+ | `links` | JSON from the id of an element a link points at to the web page that shows it (`{"…": "details.html"}`), for a drawing exported one page per file: a link to another page goes there. Only relative `.html` paths are followed |
31
33
 
32
34
  Elements the drawing makes clickable work with the mouse and the keyboard (Tab, then Enter or Space). A click plays
33
35
  a named scene on to the next one, opens a link in a new tab (only `http`, `https` and `mailto`), or shows the page a
@@ -43,7 +45,8 @@ region a click took down. A looping scene plays round until a click or next leav
43
45
 
44
46
  The element has `play()`, `pause()`, `nextScene()`, `prevScene()`, `activate(elementId)`, `currentTime`
45
47
  (settable), `duration`, `paused`, `variables` and `setState({name: value})`, and fires `load`, `frame`, `action`,
46
- `state` (with `{variables}`, after a change) and `error` events. Its page color comes from the drawing's theme; set
48
+ `state` (with `{variables}`, after a change), `page` (with `{index, name, first}`, when the page shown changes) and
49
+ `error` events. Its page color comes from the drawing's theme; set
47
50
  `--dottie-radius` to round it, and style its parts with `::part(stage)` and `::part(controls)`.
48
51
 
49
52
  Without modules, `dist/dottie-player.min.js` is a classic script that registers the element and sets
@@ -56,6 +59,21 @@ when it is showing. The classic script starts the worker from its own source (a
56
59
  loads `dottie-player.min.js` from beside itself, so host the two together. Where a worker can't start, as under a
57
60
  `worker-src` policy that refuses it, the player works it out in place as before. Small drawings always do.
58
61
 
62
+ **Click logic.** Variables can be numbers, and conditions and clicks are small expressions (`count >= 3`,
63
+ `"count + 1"`, `{count}` in a label). For more, a page can carry `logic`: JavaScript handlers a click `run`s, each
64
+ getting the variables and the click and returning new values. The player runs them only with `allow-logic`:
65
+
66
+ ```html
67
+ <dottie-player src="game.dottie" allow-logic></dottie-player>
68
+ ```
69
+
70
+ Each click's handler runs in a fresh QuickJS sandbox compiled to WebAssembly, never in your page's JavaScript: it has
71
+ no `window`, `document`, network, timers, `Date` or `Math.random`, and a time and memory limit, so the same click on
72
+ the same state gives the same result everywhere. A handler that fails leaves the state as it was and fires
73
+ `logicerror` (with `{element, handler, error}`). Without `allow-logic`, a click does its own `set` and `toggle`
74
+ instead. The engine (`dottie-logic.min.js`, about 850 KB) is loaded from beside the player only when a page with
75
+ logic is clicked, so host it with the player; `dottie-compile --allow-logic` puts it in the compiled script instead.
76
+
59
77
  **Fonts.** Text in Dottie's handwriting fonts (Caveat, Patrick Hand, Architects Daughter; SIL Open Font License)
60
78
  is drawn in them: the player loads the ones a drawing uses from `fonts/` beside its own script, as `dist/fonts` on
61
79
  npm and the CDNs. If you host the player yourself, copy that folder with it, or call `Dottie.setFontBase(url)`
@@ -78,7 +96,9 @@ handwriting fonts the drawing uses (15 to 30 KB each), so one file shows it anyw
78
96
  ```
79
97
 
80
98
  `dottie-compile` takes `--page`, `--at`, `--clean`, `--no-controls`, `--no-autoplay`, `--no-loop` and `--label`;
81
- only the chosen page (and its pictures) goes in. The Dottie Mac app's command-line tool writes the same file:
99
+ only the chosen page (and its pictures) goes in. With `--all-pages` every page goes in, for a drawing people drill
100
+ into: a link to a shape on another page shows that page, each page gets its own address (`tour.html#Details`), and
101
+ Back goes back (`--page` is then the page to start on). The Dottie Mac app's command-line tool writes the same file:
82
102
  `dottie render tour.dottie -f js`. From code: `import { compile } from "@phin-tech/dottie/compile"`.
83
103
 
84
104
  ## Use the library
package/dist/compile.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! dottie.js 0.10.0 | Apache-2.0 | https://github.com/phin-tech/dottie */
1
+ /*! dottie.js 0.11.1 | Apache-2.0 | https://github.com/phin-tech/dottie */
2
2
  var __defProp = Object.defineProperty;
3
3
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
4
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
@@ -109,12 +109,12 @@ function resolvingPalette(page) {
109
109
  }
110
110
 
111
111
  // src/model.ts
112
- var SUPPORTED_VERSION = 2;
112
+ var SUPPORTED_VERSION = 3;
113
113
  var KINDS = ["rectangle", "ellipse", "diamond", "text", "connector", "freehand", "path", "note", "image", "symbol"];
114
114
  var EASES = ["linear", "easeIn", "easeOut", "easeInOut", "hold", "spring", "bounce", "elastic"];
115
115
  var KNOWN_FIELDS = {
116
116
  file: ["version", "pages", "images"],
117
- page: ["id", "name", "layers", "elements", "theme", "customTheme", "guidesX", "guidesY", "guidesLocked", "timeline", "symbols", "variables", "flows"],
117
+ page: ["id", "name", "layers", "elements", "theme", "customTheme", "logic", "guidesX", "guidesY", "guidesLocked", "timeline", "symbols", "variables", "flows"],
118
118
  flow: ["id", "from", "to", "every", "speed", "color", "size", "when", "spread", "volume", "overrides"],
119
119
  flowOverride: ["when", "volume"],
120
120
  symbol: ["id", "name", "width", "height", "layers", "elements", "timeline", "button", "params"],
@@ -183,7 +183,7 @@ var KNOWN_FIELDS = {
183
183
  repeat: ["start", "end", "count"],
184
184
  cameraKey: ["t", "x", "y", "width", "height", "ease"],
185
185
  marker: ["t", "name", "loop"],
186
- click: ["scene", "url", "set", "toggle", "reset"],
186
+ click: ["scene", "url", "set", "toggle", "reset", "run"],
187
187
  hover: ["stroke", "fill", "opacity"],
188
188
  override: ["when", "stroke", "fill", "textColor", "opacity", "strokeWidth", "dash", "text", "reroute", "offline", "cost", "capacity", "delay"]
189
189
  };
@@ -430,7 +430,7 @@ var Reader = class {
430
430
  variables(v) {
431
431
  if (!isObj(v)) return null;
432
432
  const out = {};
433
- for (const [k, b] of Object.entries(v)) if (typeof b === "boolean") out[k] = b;
433
+ for (const [k, b] of Object.entries(v)) if (typeof b === "boolean" || typeof b === "number" && Number.isFinite(b)) out[k] = b;
434
434
  return Object.keys(out).length > 0 ? out : null;
435
435
  }
436
436
  click(v) {
@@ -442,12 +442,22 @@ var Reader = class {
442
442
  let set = null;
443
443
  if (isObj(v.set)) {
444
444
  set = {};
445
- for (const [k, b] of Object.entries(v.set)) if (typeof b === "boolean" && isName(k)) set[k] = b;
445
+ for (const [k, b] of Object.entries(v.set)) {
446
+ if (isName(k) && (typeof b === "boolean" || typeof b === "string" || typeof b === "number" && Number.isFinite(b))) set[k] = b;
447
+ }
446
448
  if (Object.keys(set).length === 0) set = null;
447
449
  }
448
450
  const raw = typeof v.toggle === "string" ? [v.toggle] : Array.isArray(v.toggle) && v.toggle.every((x) => typeof x === "string") ? v.toggle : null;
449
451
  const toggle = raw ? raw.filter(isName) : null;
450
- return { scene: str(v.scene) ?? null, url: safe, set, toggle: toggle && toggle.length > 0 ? toggle : null, reset: v.reset === true ? true : null };
452
+ const run = str(v.run);
453
+ return {
454
+ scene: str(v.scene) ?? null,
455
+ url: safe,
456
+ set,
457
+ toggle: toggle && toggle.length > 0 ? toggle : null,
458
+ reset: v.reset === true ? true : null,
459
+ run: run !== void 0 && isName(run) ? run : null
460
+ };
451
461
  }
452
462
  playback(v) {
453
463
  const s = str(v);
@@ -610,6 +620,7 @@ var Reader = class {
610
620
  elements: (Array.isArray(v.elements) ? v.elements : []).map((e) => this.element(e, images)).filter((e) => e !== null),
611
621
  theme: str(v.theme) ?? null,
612
622
  customTheme: this.customTheme(v.customTheme),
623
+ logic: typeof v.logic === "string" && v.logic.length > 0 ? v.logic : null,
613
624
  timeline: this.timeline(v.timeline),
614
625
  symbols: Array.isArray(v.symbols) ? v.symbols.map((x) => this.symbol(x, images)).filter((x) => x !== null) : null,
615
626
  variables: this.variables(v.variables),
@@ -751,6 +762,11 @@ function playerAttributes(options) {
751
762
  if (options.noAutoplay) out["no-autoplay"] = "";
752
763
  if (options.noLoop) out["no-loop"] = "";
753
764
  if (options.label !== void 0) out.label = options.label;
765
+ if (options.logicEngine) out["allow-logic"] = "";
766
+ if (options.allPages) {
767
+ out.history = "";
768
+ if (options.page !== void 0) out.page = String(options.page);
769
+ }
754
770
  return out;
755
771
  }
756
772
  function compile(source, runtime, options = {}) {
@@ -765,28 +781,32 @@ function compile(source, runtime, options = {}) {
765
781
  const file = parseDottie(raw);
766
782
  const json = raw;
767
783
  const i = pageIndex(file, options.page === void 0 ? null : String(options.page));
768
- const page = json.pages[i];
784
+ const chosen = options.allPages ? json.pages.map((_, k) => k) : [i];
785
+ const pages = chosen.map((k) => json.pages[k]);
769
786
  const refs = /* @__PURE__ */ new Set();
770
- JSON.stringify(page, (k, v) => {
787
+ JSON.stringify(pages, (k, v) => {
771
788
  if (k === "ref" && typeof v === "string") refs.add(v);
772
789
  return v;
773
790
  });
774
791
  const images = Object.fromEntries(Object.entries(json.images ?? {}).filter(([k]) => refs.has(k)));
775
- const data = { version: json.version, pages: [page] };
792
+ const data = { version: json.version, pages };
776
793
  if (Object.keys(images).length) data.images = images;
777
794
  const fonts = {};
778
- for (const family of options.fontData ? usedFonts(file.pages[i]) : []) {
795
+ const families2 = new Set(chosen.flatMap((k) => options.fontData ? usedFonts(file.pages[k]) : []));
796
+ for (const family of families2) {
779
797
  for (const face of fontFaces(family)) {
780
798
  const b64 = options.fontData(family, face);
781
799
  if (b64) (fonts[family] ?? (fonts[family] = {}))[face] = b64;
782
800
  }
783
801
  }
802
+ const logic = chosen.some((k) => file.pages[k].logic);
784
803
  const fill = {
785
804
  DOTTIE_DATA: () => scriptJSON(data),
786
- DOTTIE_OPTIONS: () => scriptJSON(playerAttributes(options)),
805
+ DOTTIE_OPTIONS: () => scriptJSON(playerAttributes(logic ? options : { ...options, logicEngine: void 0 })),
787
806
  DOTTIE_FONTS: () => scriptJSON(fonts)
788
807
  };
789
- return runtime.trimEnd() + "\n" + LOADER.replace(/\bDOTTIE_(?:DATA|OPTIONS|FONTS)\b/g, (m) => fill[m]());
808
+ const engine = options.logicEngine && logic ? options.logicEngine.trimEnd() + "\n" : "";
809
+ return engine + runtime.trimEnd() + "\n" + LOADER.replace(/\bDOTTIE_(?:DATA|OPTIONS|FONTS)\b/g, (m) => fill[m]());
790
810
  }
791
811
  export {
792
812
  LOADER,
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- /*! dottie.js 0.10.0 | Apache-2.0 | https://github.com/phin-tech/dottie */
2
+ /*! dottie.js 0.11.1 | Apache-2.0 | https://github.com/phin-tech/dottie */
3
3
  var __defProp = Object.defineProperty;
4
4
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5
5
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
@@ -117,12 +117,12 @@ function resolvingPalette(page) {
117
117
  }
118
118
 
119
119
  // src/model.ts
120
- var SUPPORTED_VERSION = 2;
120
+ var SUPPORTED_VERSION = 3;
121
121
  var KINDS = ["rectangle", "ellipse", "diamond", "text", "connector", "freehand", "path", "note", "image", "symbol"];
122
122
  var EASES = ["linear", "easeIn", "easeOut", "easeInOut", "hold", "spring", "bounce", "elastic"];
123
123
  var KNOWN_FIELDS = {
124
124
  file: ["version", "pages", "images"],
125
- page: ["id", "name", "layers", "elements", "theme", "customTheme", "guidesX", "guidesY", "guidesLocked", "timeline", "symbols", "variables", "flows"],
125
+ page: ["id", "name", "layers", "elements", "theme", "customTheme", "logic", "guidesX", "guidesY", "guidesLocked", "timeline", "symbols", "variables", "flows"],
126
126
  flow: ["id", "from", "to", "every", "speed", "color", "size", "when", "spread", "volume", "overrides"],
127
127
  flowOverride: ["when", "volume"],
128
128
  symbol: ["id", "name", "width", "height", "layers", "elements", "timeline", "button", "params"],
@@ -191,7 +191,7 @@ var KNOWN_FIELDS = {
191
191
  repeat: ["start", "end", "count"],
192
192
  cameraKey: ["t", "x", "y", "width", "height", "ease"],
193
193
  marker: ["t", "name", "loop"],
194
- click: ["scene", "url", "set", "toggle", "reset"],
194
+ click: ["scene", "url", "set", "toggle", "reset", "run"],
195
195
  hover: ["stroke", "fill", "opacity"],
196
196
  override: ["when", "stroke", "fill", "textColor", "opacity", "strokeWidth", "dash", "text", "reroute", "offline", "cost", "capacity", "delay"]
197
197
  };
@@ -438,7 +438,7 @@ var Reader = class {
438
438
  variables(v) {
439
439
  if (!isObj(v)) return null;
440
440
  const out = {};
441
- for (const [k, b] of Object.entries(v)) if (typeof b === "boolean") out[k] = b;
441
+ for (const [k, b] of Object.entries(v)) if (typeof b === "boolean" || typeof b === "number" && Number.isFinite(b)) out[k] = b;
442
442
  return Object.keys(out).length > 0 ? out : null;
443
443
  }
444
444
  click(v) {
@@ -450,12 +450,22 @@ var Reader = class {
450
450
  let set = null;
451
451
  if (isObj(v.set)) {
452
452
  set = {};
453
- for (const [k, b] of Object.entries(v.set)) if (typeof b === "boolean" && isName(k)) set[k] = b;
453
+ for (const [k, b] of Object.entries(v.set)) {
454
+ if (isName(k) && (typeof b === "boolean" || typeof b === "string" || typeof b === "number" && Number.isFinite(b))) set[k] = b;
455
+ }
454
456
  if (Object.keys(set).length === 0) set = null;
455
457
  }
456
458
  const raw = typeof v.toggle === "string" ? [v.toggle] : Array.isArray(v.toggle) && v.toggle.every((x) => typeof x === "string") ? v.toggle : null;
457
459
  const toggle = raw ? raw.filter(isName) : null;
458
- return { scene: str(v.scene) ?? null, url: safe, set, toggle: toggle && toggle.length > 0 ? toggle : null, reset: v.reset === true ? true : null };
460
+ const run = str(v.run);
461
+ return {
462
+ scene: str(v.scene) ?? null,
463
+ url: safe,
464
+ set,
465
+ toggle: toggle && toggle.length > 0 ? toggle : null,
466
+ reset: v.reset === true ? true : null,
467
+ run: run !== void 0 && isName(run) ? run : null
468
+ };
459
469
  }
460
470
  playback(v) {
461
471
  const s = str(v);
@@ -618,6 +628,7 @@ var Reader = class {
618
628
  elements: (Array.isArray(v.elements) ? v.elements : []).map((e) => this.element(e, images)).filter((e) => e !== null),
619
629
  theme: str(v.theme) ?? null,
620
630
  customTheme: this.customTheme(v.customTheme),
631
+ logic: typeof v.logic === "string" && v.logic.length > 0 ? v.logic : null,
621
632
  timeline: this.timeline(v.timeline),
622
633
  symbols: Array.isArray(v.symbols) ? v.symbols.map((x) => this.symbol(x, images)).filter((x) => x !== null) : null,
623
634
  variables: this.variables(v.variables),
@@ -759,6 +770,11 @@ function playerAttributes(options2) {
759
770
  if (options2.noAutoplay) out["no-autoplay"] = "";
760
771
  if (options2.noLoop) out["no-loop"] = "";
761
772
  if (options2.label !== void 0) out.label = options2.label;
773
+ if (options2.logicEngine) out["allow-logic"] = "";
774
+ if (options2.allPages) {
775
+ out.history = "";
776
+ if (options2.page !== void 0) out.page = String(options2.page);
777
+ }
762
778
  return out;
763
779
  }
764
780
  function compile(source2, runtime, options2 = {}) {
@@ -773,32 +789,36 @@ function compile(source2, runtime, options2 = {}) {
773
789
  const file = parseDottie(raw);
774
790
  const json = raw;
775
791
  const i = pageIndex(file, options2.page === void 0 ? null : String(options2.page));
776
- const page = json.pages[i];
792
+ const chosen = options2.allPages ? json.pages.map((_, k) => k) : [i];
793
+ const pages = chosen.map((k) => json.pages[k]);
777
794
  const refs = /* @__PURE__ */ new Set();
778
- JSON.stringify(page, (k, v) => {
795
+ JSON.stringify(pages, (k, v) => {
779
796
  if (k === "ref" && typeof v === "string") refs.add(v);
780
797
  return v;
781
798
  });
782
799
  const images = Object.fromEntries(Object.entries(json.images ?? {}).filter(([k]) => refs.has(k)));
783
- const data = { version: json.version, pages: [page] };
800
+ const data = { version: json.version, pages };
784
801
  if (Object.keys(images).length) data.images = images;
785
802
  const fonts = {};
786
- for (const family of options2.fontData ? usedFonts(file.pages[i]) : []) {
803
+ const families2 = new Set(chosen.flatMap((k) => options2.fontData ? usedFonts(file.pages[k]) : []));
804
+ for (const family of families2) {
787
805
  for (const face of fontFaces(family)) {
788
806
  const b64 = options2.fontData(family, face);
789
807
  if (b64) (fonts[family] ?? (fonts[family] = {}))[face] = b64;
790
808
  }
791
809
  }
810
+ const logic = chosen.some((k) => file.pages[k].logic);
792
811
  const fill = {
793
812
  DOTTIE_DATA: () => scriptJSON(data),
794
- DOTTIE_OPTIONS: () => scriptJSON(playerAttributes(options2)),
813
+ DOTTIE_OPTIONS: () => scriptJSON(playerAttributes(logic ? options2 : { ...options2, logicEngine: void 0 })),
795
814
  DOTTIE_FONTS: () => scriptJSON(fonts)
796
815
  };
797
- return runtime.trimEnd() + "\n" + LOADER.replace(/\bDOTTIE_(?:DATA|OPTIONS|FONTS)\b/g, (m) => fill[m]());
816
+ const engine = options2.logicEngine && logic ? options2.logicEngine.trimEnd() + "\n" : "";
817
+ return engine + runtime.trimEnd() + "\n" + LOADER.replace(/\bDOTTIE_(?:DATA|OPTIONS|FONTS)\b/g, (m) => fill[m]());
798
818
  }
799
819
 
800
820
  // src/index.ts
801
- var VERSION = "0.10.0";
821
+ var VERSION = "0.11.1";
802
822
 
803
823
  // src/cli.ts
804
824
  var usage = `dottie-compile ${VERSION}: a Dottie drawing as one script that plays it on any page.
@@ -812,9 +832,12 @@ USAGE
812
832
  OPTIONS
813
833
  -o, --output <path> Where to write it ("-" for stdout); default drawing.js next to the input
814
834
  -p, --page <page> Page name or 1-based number; only that page is included (default the first)
835
+ --all-pages Include every page, with links between them working and Back going back (with
836
+ --page, the page to start on)
815
837
  --at <seconds> Show that moment as a still
816
838
  --clean Draw precisely instead of sketchy
817
839
  --no-controls, --no-autoplay, --no-loop
840
+ --allow-logic let the page's click logic run (ADR 0007); it carries the engine (about 850 KB)
818
841
  --label <text> The player's accessible name
819
842
  `;
820
843
  function fail(message, code = 2) {
@@ -824,6 +847,7 @@ function fail(message, code = 2) {
824
847
  }
825
848
  var args = process.argv.slice(2);
826
849
  var options = {};
850
+ var allowLogic = false;
827
851
  var input;
828
852
  var output;
829
853
  for (let i = 0; i < args.length; i++) {
@@ -853,6 +877,9 @@ for (let i = 0; i < args.length; i++) {
853
877
  options.at = t;
854
878
  break;
855
879
  }
880
+ case "--all-pages":
881
+ options.allPages = true;
882
+ break;
856
883
  case "--clean":
857
884
  options.clean = true;
858
885
  break;
@@ -865,6 +892,9 @@ for (let i = 0; i < args.length; i++) {
865
892
  case "--no-loop":
866
893
  options.noLoop = true;
867
894
  break;
895
+ case "--allow-logic":
896
+ allowLogic = true;
897
+ break;
868
898
  case "--label":
869
899
  options.label = value();
870
900
  break;
@@ -895,7 +925,8 @@ try {
895
925
  return void 0;
896
926
  }
897
927
  };
898
- const js = compile(source, runtime, { ...options, fontData });
928
+ const logicEngine = allowLogic ? readFileSync(new URL("./dottie-logic.min.js", import.meta.url), "utf8") : void 0;
929
+ const js = compile(source, runtime, { ...options, fontData, logicEngine });
899
930
  if (output === "-") process.stdout.write(js);
900
931
  else {
901
932
  const target = output ?? input.replace(/\.dottie$/i, "") + ".js";