@shotstack/cli 0.14.0 → 0.15.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shotstack/cli",
3
- "version": "0.14.0",
3
+ "version": "0.15.1",
4
4
  "description": "Command-line interface for the Shotstack video rendering API.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/shotstack/shotstack-cli",
@@ -15,9 +15,9 @@ This skill loads in **terminal-based AI agents** (Claude Code, Cursor, Codex CLI
15
15
 
16
16
  ## Check versions once per session
17
17
 
18
- This skill is version **0.14.0** and needs `@shotstack/cli` **0.13.0** or later. Before the first `shotstack` command in a session:
18
+ This skill is version **0.15.1** and needs `@shotstack/cli` **0.15.0** or later. Before the first `shotstack` command in a session:
19
19
 
20
- 1. Run `shotstack --version`. If it is older than 0.13.0, tell the user: what this skill documents, such as `analyze`, is missing until they run `npm install -g @shotstack/cli@latest`.
20
+ 1. Run `shotstack --version`. If it is older than 0.15.0, tell the user: what this skill documents, such as the html5 size steps from `ingest upload --watch`, is missing until they run `npm install -g @shotstack/cli@latest`.
21
21
  2. Run `npm view @shotstack/cli version`. If it is newer than this skill's version, tell the user an update is available and ask whether to install it. Only on a yes, run `npx skills update shotstack -y` and `npm install -g @shotstack/cli@latest`. Never update without asking. `npx skills check` is not a read-only check: it installs the update.
22
22
 
23
23
  If a check fails (no network, no npm, a sandbox), skip it and carry on.
@@ -95,7 +95,7 @@ What you can build inside one `html5` clip, listed by the effect you'd reach for
95
95
  |---|---|---|
96
96
  | Particles, generative art | Canvas 2D drawn from `window.__shotstackSeek = (ms) => { … }` with seeded positions; or DOM dots with `physics2D` | Match |
97
97
  | Charts and data viz | D3 builds SVG, GSAP animates it (see the bar-chart example in [`html5.md`](html5.md)) | Match |
98
- | Lottie animation | `lottie.loadAnimation({ container, renderer: "svg", autoplay: false, loop: false, animationData })`. Shapes, stroke write-ons, masks, mattes and nested compositions work | Caveat: expressions don't run; convert them to keyframes first |
98
+ | Lottie animation | `lottie.loadAnimation({ container, renderer: "svg", autoplay: false, loop: false, animationData })`. Shapes, stroke write-ons, masks, mattes, nested compositions and common expressions work | Caveat: Lottie runs a subset of After Effects expressions; bake any it misses into keyframes |
99
99
 
100
100
  ## Not available
101
101
 
@@ -11,7 +11,7 @@ This is the **modern replacement for the deprecated `html` asset.** `html5` runs
11
11
  - Required and optional fields
12
12
  - Preloaded libraries
13
13
  - The browser harness (deterministic auto-seek)
14
- - Sandbox restrictions: no network; ingested images and fonts by URL, everything else inline
14
+ - Sandbox restrictions: no network; ingested images and fonts by URL, everything else inline (incl. Lottie exports)
15
15
  - Sizing
16
16
  - 3D: what renders in preview and render
17
17
  - Worked example: animated lower-third (GSAP)
@@ -53,7 +53,7 @@ Four libraries and GSAP's plugins are always available — no `<script src=>` ta
53
53
  - **GSAP** (`window.gsap`) — primary animation library. Use timelines (`gsap.timeline()`) over loose tweens; the harness seeks timelines correctly.
54
54
  - **anime.js** (`window.anime`) — alternative animation library.
55
55
  - **D3** (`window.d3`) — for data binding, scales, and SVG/DOM construction. Pair with GSAP for the actual animation; D3's transitions work too but GSAP is more reliable under seek. `d3.randomLcg(seed)` is the seeded random source.
56
- - **Lottie** (`window.lottie`) — Bodymovin JSON player (SVG-renderer build; `renderer: "canvas"` is unavailable). Expressions in the file (`wiggle`, `loopOut`) don't run: a layer that carries one doesn't render. Bake expressions into keyframes before export (After Effects: *Animation → Keyframe Assistant → Convert Expression to Keyframes*).
56
+ - **Lottie** (`window.lottie`) — Bodymovin JSON player (SVG-renderer build; `renderer: "canvas"` is unavailable). Expressions in the file (`wiggle`, `loopOut`, slider links) run in Lottie's own engine, which covers a subset of After Effects expressions. If one doesn't animate as it does in After Effects, bake it into keyframes before export (*Animation → Keyframe Assistant → Convert Expression to Keyframes*). Size, image and text rules are under *Lottie exports* below.
57
57
 
58
58
  GSAP 3.15 plugins, already registered:
59
59
 
@@ -94,7 +94,7 @@ Frames are captured by **seeking** the animation to each timestamp, not by playi
94
94
  The iframe renders under a strict Content-Security-Policy (`default-src 'none'`), in both Studio preview and cloud render. Nothing is fetched from the network at render time:
95
95
 
96
96
  - **No external `<script src=>`.** Only the bundled GSAP/anime.js/D3/Lottie run (they're inlined for you). Another library would have to be inlined into your `js` — and must be seekable.
97
- - **No `fetch` / `XMLHttpRequest`** (`connect-src 'none'`). Bundle any data inline — e.g. the JS array in the bar-chart example.
97
+ - **`fetch` / `XMLHttpRequest` read `data:` URIs only** (`connect-src data:`). Bundle any data inline — e.g. the JS array in the bar-chart example.
98
98
  - **No remote images** (`img-src 'self' data: blob:`), except images you ingested (below). Otherwise embed images as `data:` URIs. A `data:image/svg+xml` background is fine.
99
99
  - **No remote fonts** (`font-src 'self' data:`), except fonts you ingested (below). See *Fonts in HTML5*.
100
100
 
@@ -119,6 +119,9 @@ FONT=$(shotstack ingest upload ./Brand.woff2 --watch --output json | tail -n1 |
119
119
  - **Same account and environment only.** A file ingested on `stage` works in `stage` renders, not in `v1`, and another account's files are refused. Every other remote URL is still blocked.
120
120
  - **10 MiB per file, 25 MiB per page.** A file counts once for every place the page references it, so reference a large image once (a CSS class, say) and reuse the class.
121
121
  - **Size images to the clip.** A photo much larger than the clip makes a heavier page and a slower capture. If the source has a WebP rendition named `html5-512`, `html5-1024`, `html5-2048` or `html5-4096`, the renderer uses the smallest one that covers the clip's longest edge; otherwise it uses the original.
122
+ <!-- surface:cli -->
123
+ - `shotstack ingest upload --watch` and `ingest fetch --watch` request those renditions for an image and wait up to 60 s for them, so the `source` URL is all the page needs.
124
+ <!-- /surface -->
122
125
  - **A file that can't be used fails the render**, for example one that's missing, too large, or not an image or font.
123
126
  - **Studio's preview doesn't load ingested files yet**, so they show as missing there. The render is unaffected.
124
127
  <!-- surface:cli -->
@@ -142,6 +145,27 @@ FONT=$(shotstack ingest upload ./Brand.woff2 --watch --output json | tail -n1 |
142
145
 
143
146
  An unresolved family silently falls back to the browser default — the render won't fail, but the text won't be your font. For a single styled line, a `rich-text` asset (which *does* use `timeline.fonts[]`; verified catalogue in `shared/agent-core.md`) is simpler than a `data:` font embed.
144
147
 
148
+ ### Lottie exports
149
+
150
+ Pass the export as `animationData` with `autoplay: false`; loading it by `path` is a network fetch and fails. In Bodymovin, tick *Include in json* so images travel inside the file as `data:` URIs. A data file that expressions read (a JSON layer) must be a `data:` URI in the asset's `p`, with `e: 1`.
151
+
152
+ **Size.** The whole Edit JSON must be under 390 KB, and most 1080p exports are larger. Gzip the export, put it in `js` as base64, and unpack it in the page. A 1.7 MB export packs to about 390 KB:
153
+
154
+ <!-- surface:cli -->
155
+ `gzip -9 -c data.json | base64 | tr -d '\n'` prints the base64 string.
156
+ <!-- /surface -->
157
+
158
+ ```js
159
+ (async () => {
160
+ const bytes = Uint8Array.from(atob("H4sI…"), (c) => c.charCodeAt(0));
161
+ const gunzip = new Blob([bytes]).stream().pipeThrough(new DecompressionStream("gzip"));
162
+ const animationData = await new Response(gunzip).json();
163
+ lottie.loadAnimation({ container: document.getElementById("anim"), renderer: "svg", autoplay: false, loop: false, animationData });
164
+ })();
165
+ ```
166
+
167
+ **Text.** Exported with *Glyphs* ticked, text is drawn as shapes, but only for the characters in the export: any other character in text you change later (with a merge field, say) silently disappears, so "Hi Sydney, 2026!" renders as "i Sydney". For text that changes, untick *Glyphs* and load the font under the family name the export uses (see *Fonts in HTML5*). Don't leave Bodymovin's Google Fonts or Typekit URL in the file: it can't load, and Lottie draws nothing at all for about five seconds while it waits, which blanks the opening frames.
168
+
145
169
  ## Sizing
146
170
 
147
171
  The single most important rule: **size the clip to the content, not to the canvas.** Then position with `offset`.
@@ -85,6 +85,11 @@ An `html5` page can use images and fonts you ingested by putting their
85
85
  The file must belong to the same account and environment as the render. Limits
86
86
  and details are in [`html5.md`](html5.md).
87
87
 
88
+ With `--watch`, an image upload or fetch also requests smaller WebP copies
89
+ (`html5-512` up to `html5-4096`, only those smaller than the image) and waits
90
+ up to 60 s for them. They're listed under `outputs.renditions`; the renderer
91
+ picks one for the clip size, so keep using the `source` URL.
92
+
88
93
  ## Fetch a remote URL instead of uploading
89
94
 
90
95
  If the media is already at a URL but you want Shotstack to host its own copy