@shotstack/cli 0.7.1 → 0.8.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.7.1",
3
+ "version": "0.8.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",
@@ -27,7 +27,7 @@
27
27
  "test": "bun test"
28
28
  },
29
29
  "dependencies": {
30
- "@shotstack/schemas": "^1.12.2",
30
+ "@shotstack/schemas": "^1.17.0",
31
31
  "commander": "^12.1.0",
32
32
  "zod": "^4.4.3"
33
33
  },
@@ -13,7 +13,9 @@ license: Apache-2.0
13
13
 
14
14
  This skill loads in **terminal-based AI agents** (Claude Code, Cursor, Codex CLI, Gemini CLI, etc.). All operations here are shell commands. There is no embedded UI, no iframe, no inline canvas, no MCP tool surface — only `shotstack` invocations from a terminal. To hand off to a human, run `shotstack studio <file>`; this opens the user's default browser to a `shotstack.studio` URL. Tell the user to click Render *in the browser tab*, not in any UI inside the terminal.
15
15
 
16
- Commands for the Shotstack video rendering API. `render` submits an Edit JSON and returns a render ID; `status` polls a render until done. `ingest` uploads your own local files (or fetches remote URLs) and hosts them so they can be referenced from an Edit. `validate` lints an Edit — run it before every render. `studio` opens an edit in the browser editor for a human to preview, tweak, and render.
16
+ **Open-ended first render? Ask before composing.** If the ask doesn't state what the video is (subject, format or destination) — e.g. "render my first video", "make me a video", "set up Shotstack" — read [`references/onboarding.md`](references/onboarding.md) and ask its discovery questions, then WAIT for answers. Do not write an Edit first. An open-ended ask is not a specification, and a stray JSON file in the project doesn't make the user experienced. Compose without asking only when the user has stated what the video is, or explicitly says to just show anything.
17
+
18
+ Commands for the Shotstack video rendering API. `render` submits an Edit JSON and returns a render ID; `status` polls a render until done. `ingest` uploads your own local files (or fetches remote URLs) and hosts them so they can be referenced from an Edit. `validate` lints an Edit — run it before every render. `studio` opens an edit in the browser editor for a human to preview, tweak, and render. `template list|get|create|update|delete` reads and writes templates saved to the account: `list` shows saved templates (id + name); `get <id>` fetches a saved template's Edit JSON (e.g. one the user designed in Studio) so you can render or remix it; `create <file> --name <name>` saves an edit as a new template; `update <id> <file>` overwrites one; `delete <id>` removes one.
17
19
 
18
20
  **Default loop — no API key required:** compose → `validate` (offline lint) → `studio` (browser preview). Only the API-backed commands (`render`, `status`, `ingest`) need a key. Reach for `render` when you specifically need a final MP4 exported in the cloud; reach for `studio` for everything else — it is the cheapest way to see an edit and the right default for any creative a human will review.
19
21
 
@@ -151,6 +153,7 @@ Authoritative sources, in order of preference:
151
153
 
152
154
  This skill ships sub-references for the gnarly bits:
153
155
 
156
+ - [`references/onboarding.md`](references/onboarding.md) — first-render discovery interview for new users: what to ask, and how answers map to a first Edit
154
157
  - [`references/ingest.md`](references/ingest.md) — uploading local files (and fetching URLs) so they can be used in an Edit: the upload→render workflow, `--watch`, status values, supported types
155
158
  - [`references/timeline.md`](references/timeline.md) — track layering, transitions, background music via audio assets
156
159
  - [`references/positioning.md`](references/positioning.md) — coordinate model, `position`/`offset` (fraction of frame, +y up), clip bounding box & `fit`, text sizing, transform order
@@ -34,26 +34,9 @@ Load a font from a public URL via `timeline.fonts[]`, then reference its **file
34
34
 
35
35
  The `font.family` value is the URL's filename without extension, and it **must** match the URL's basename exactly. For URL `https://fonts.gstatic.com/s/montserrat/v31/JTUSjIg1_i6t8kCHKm45xW5rygbi49c.ttf`, family = `JTUSjIg1_i6t8kCHKm45xW5rygbi49c`. If `family` and the URL basename diverge, the font silently fails to load.
36
36
 
37
- ## Verified font catalogue (12 fonts)
37
+ ## Verified font catalogue
38
38
 
39
- Copied verbatim from the Studio SDK catalogue. Paste the **url** into `timeline.fonts[].src`, paste the **family** into `asset.font.family`.
40
-
41
- | Font (style) | family (use in `font.family`) | url (use in `timeline.fonts[].src`) |
42
- |---|---|---|
43
- | Inter (sans, variable) | `UcCo3FwrK3iLTfvlaQc78lA2` | `https://fonts.gstatic.com/s/inter/v20/UcCo3FwrK3iLTfvlaQc78lA2.ttf` |
44
- | Roboto (sans, variable) | `KFOmCnqEu92Fr1Me5WZLCzYlKw` | `https://fonts.gstatic.com/s/roboto/v50/KFOmCnqEu92Fr1Me5WZLCzYlKw.ttf` |
45
- | Open Sans (sans, variable) | `mem8YaGs126MiZpBA-U1UpcaXcl0Aw` | `https://fonts.gstatic.com/s/opensans/v44/mem8YaGs126MiZpBA-U1UpcaXcl0Aw.ttf` |
46
- | Montserrat (sans, variable) | `JTUSjIg1_i6t8kCHKm45xW5rygbi49c` | `https://fonts.gstatic.com/s/montserrat/v31/JTUSjIg1_i6t8kCHKm45xW5rygbi49c.ttf` |
47
- | Poppins (sans) | `pxiEyp8kv8JHgFVrFJDUc1NECPY` | `https://fonts.gstatic.com/s/poppins/v24/pxiEyp8kv8JHgFVrFJDUc1NECPY.ttf` |
48
- | DM Sans (sans, variable) | `rP2Hp2ywxg089UriOZSCHBeHFl0` | `https://fonts.gstatic.com/s/dmsans/v17/rP2Hp2ywxg089UriOZSCHBeHFl0.ttf` |
49
- | Nunito (sans, variable) | `XRXV3I6Li01BKof4MuyAbsrVcA` | `https://fonts.gstatic.com/s/nunito/v32/XRXV3I6Li01BKof4MuyAbsrVcA.ttf` |
50
- | Raleway (sans, variable) | `1Ptug8zYS_SKggPN-CoCTqluHfE` | `https://fonts.gstatic.com/s/raleway/v37/1Ptug8zYS_SKggPN-CoCTqluHfE.ttf` |
51
- | Oswald (display, variable) | `TK3iWkUHHAIjg75GHjUHte5fKg` | `https://fonts.gstatic.com/s/oswald/v57/TK3iWkUHHAIjg75GHjUHte5fKg.ttf` |
52
- | Bebas Neue (display) | `JTUSjIg69CK48gW7PXooxW5rygbi49c` | `https://fonts.gstatic.com/s/bebasneue/v16/JTUSjIg69CK48gW7PXooxW5rygbi49c.ttf` |
53
- | Anton (display) | `1Ptgg87LROyAm0K08i4gS7lu` | `https://fonts.gstatic.com/s/anton/v27/1Ptgg87LROyAm0K08i4gS7lu.ttf` |
54
- | Playfair Display (serif, variable) | `nuFiD-vYSZviVYUb_rj3ij__anPXPTvSgWE_-xU` | `https://fonts.gstatic.com/s/playfairdisplay/v40/nuFiD-vYSZviVYUb_rj3ij__anPXPTvSgWE_-xU.ttf` |
55
-
56
- Variable fonts (most of the above) cover the full weight range (100–900) from a single URL — set `font.weight` in the clip. For the non-variable fonts (Poppins, Bebas Neue, Anton) the registered URL is weight 400; the SDK falls back gracefully when you request a bolder weight.
39
+ The verified 12-font catalogue lives in [`shared/agent-core.md`](../shared/agent-core.md) (Fonts section) — the single copy, so it can't drift. Copy entries from there verbatim. Non-variable fonts in that table (Poppins, Bebas Neue, Anton) register at weight 400; the SDK falls back gracefully when you request a bolder weight.
57
40
 
58
41
  ### Sourcing more fonts
59
42
 
@@ -82,7 +82,7 @@ The iframe renders under a strict Content-Security-Policy (`default-src 'none'`)
82
82
  ```
83
83
  2. **Use a system family** (`system-ui`, `Arial`, `Georgia`, …) — resolves in the render browser with no load.
84
84
 
85
- 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 `references/fonts.md`) is simpler than a `data:` font embed.
85
+ 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.
86
86
 
87
87
  ## Sizing
88
88
 
@@ -0,0 +1,71 @@
1
+ # First render: discovery interview
2
+
3
+ **The gate: do not compose an Edit until the user has answered the questions
4
+ below (or explicitly said "just show me anything").** Setting up the CLI and
5
+ key can proceed; writing the video cannot.
6
+
7
+ "Render my first video" is not a specification. It says nothing about the
8
+ subject, the content, the format or where the video will go. Neither does
9
+ "set up Shotstack". If any of those are unstated, ask. A first video is only
10
+ useful when it matches what the user is actually trying to make, and a short
11
+ interview gets there faster than guessing.
12
+
13
+ Skip the interview only when the user has stated what the video is (e.g.
14
+ "make a 9:16 promo from the images in ./assets with the tagline X"), or has
15
+ declined to answer.
16
+
17
+ ## The interview
18
+
19
+ Ask conversationally, batched into one or two messages, and wait for the
20
+ reply. Skip any question the project already answers (e.g. a Next.js
21
+ e-commerce app full of product images answers question 2).
22
+
23
+ 1. **What should the video do?** Social clips, product or listing videos,
24
+ personalised outreach, in-app content, something else? Listen for the job,
25
+ not the feature.
26
+ 2. **What content or data exists?** Images, footage, audio or brand assets in
27
+ the project or at URLs; structured data (CSV, JSON, database, CMS) that
28
+ could drive repeated or personalised videos.
29
+ 3. **Where will the videos go?** Destination decides format: 9:16 for
30
+ TikTok/Reels/Shorts, 1:1 or 4:5 for feeds, 16:9 for YouTube/web. When in
31
+ doubt for social, default to 1080x1920 (9:16).
32
+ 4. **One video or many?** Both make fine first renders, but the composition
33
+ differs: pipelines should use merge fields from the start.
34
+
35
+ ## From answers to a first render
36
+
37
+ - Compose ONE Edit JSON that answers the four questions. Make it something
38
+ worth keeping, not a minimal demo.
39
+ - Use the user's real assets when they exist (host local files first:
40
+ `shotstack ingest upload <file> --watch`, then reference the returned URL).
41
+ If nothing is to hand, build from the Shotstack asset library
42
+ (`references/asset-library.md`) and motion-graphic snippets
43
+ (`references/html5-snippets.md`), matched to their stated use case.
44
+ - Use their brand where it exists: colours, fonts and logos from the project
45
+ or their site rather than an invented look. Follow the house motion
46
+ language (`references/motion.md`).
47
+ - If they chose "many": add merge fields (`{{ placeholder }}`) for the parts
48
+ that vary per video, and show one render with sample values.
49
+ - Loop: compose, then `shotstack validate`, then `shotstack render edit.json
50
+ --env stage --watch`.
51
+
52
+ ## Wrapping up
53
+
54
+ - Give two links, always: the rendered MP4 and a Studio link (`shotstack
55
+ studio <file> --no-open`, include the printed shotstack.studio URL). The
56
+ Studio link lets the user tweak the design in the browser without touching
57
+ JSON; say so.
58
+ - Describe what they have in plain terms: a reusable template, free stage
59
+ renders, the same JSON in production via `--env v1`, merge fields for the
60
+ parts that vary. Don't surface validator warnings or internal caveats
61
+ unless something is actually broken.
62
+ - End by offering to take the next step towards what they said in the
63
+ interview, concretely, not a generic list. They wanted a data-driven
64
+ pipeline: offer to wire the template to their data source and render a
65
+ batch now. They mentioned their own footage: offer to upload it and swap it
66
+ in. One sharp offer beats five open-ended suggestions.
67
+
68
+ ## Tone
69
+
70
+ Brisk, concrete and curious about the user's project. Batch questions, don't
71
+ drip-feed. One good clarifying question beats three generic ones.
@@ -266,7 +266,26 @@ Use **custom Google Fonts via `timeline.fonts[]`**. System fonts (`Arial`, `Helv
266
266
 
267
267
  **CRITICAL: Do NOT construct or fabricate Google Fonts URLs from memory.** Google rotates them (`v26 → v31 → ...`) and the hash filenames change with each version. Any URL you reconstruct from training data is almost certainly a 404. **Use ONLY the verified entries below, copied verbatim.**
268
268
 
269
- See `references/fonts.md` for how to source fonts from the Studio SDK catalogue and the built-in fallback fonts.
269
+ ### Verified font catalogue (12 fonts)
270
+
271
+ Paste the **url** into `timeline.fonts[].src`, paste the **family** into `asset.font.family`.
272
+
273
+ | Font (style) | family (use in `font.family`) | url (use in `timeline.fonts[].src`) |
274
+ |---|---|---|
275
+ | Inter (sans, variable) | `UcCo3FwrK3iLTfvlaQc78lA2` | `https://fonts.gstatic.com/s/inter/v20/UcCo3FwrK3iLTfvlaQc78lA2.ttf` |
276
+ | Roboto (sans, variable) | `KFOmCnqEu92Fr1Me5WZLCzYlKw` | `https://fonts.gstatic.com/s/roboto/v50/KFOmCnqEu92Fr1Me5WZLCzYlKw.ttf` |
277
+ | Open Sans (sans, variable) | `mem8YaGs126MiZpBA-U1UpcaXcl0Aw` | `https://fonts.gstatic.com/s/opensans/v44/mem8YaGs126MiZpBA-U1UpcaXcl0Aw.ttf` |
278
+ | Montserrat (sans, variable) | `JTUSjIg1_i6t8kCHKm45xW5rygbi49c` | `https://fonts.gstatic.com/s/montserrat/v31/JTUSjIg1_i6t8kCHKm45xW5rygbi49c.ttf` |
279
+ | Poppins (sans) | `pxiEyp8kv8JHgFVrFJDUc1NECPY` | `https://fonts.gstatic.com/s/poppins/v24/pxiEyp8kv8JHgFVrFJDUc1NECPY.ttf` |
280
+ | DM Sans (sans, variable) | `rP2Hp2ywxg089UriOZSCHBeHFl0` | `https://fonts.gstatic.com/s/dmsans/v17/rP2Hp2ywxg089UriOZSCHBeHFl0.ttf` |
281
+ | Nunito (sans, variable) | `XRXV3I6Li01BKof4MuyAbsrVcA` | `https://fonts.gstatic.com/s/nunito/v32/XRXV3I6Li01BKof4MuyAbsrVcA.ttf` |
282
+ | Raleway (sans, variable) | `1Ptug8zYS_SKggPN-CoCTqluHfE` | `https://fonts.gstatic.com/s/raleway/v37/1Ptug8zYS_SKggPN-CoCTqluHfE.ttf` |
283
+ | Oswald (display, variable) | `TK3iWkUHHAIjg75GHjUHte5fKg` | `https://fonts.gstatic.com/s/oswald/v57/TK3iWkUHHAIjg75GHjUHte5fKg.ttf` |
284
+ | Bebas Neue (display) | `JTUSjIg69CK48gW7PXooxW5rygbi49c` | `https://fonts.gstatic.com/s/bebasneue/v16/JTUSjIg69CK48gW7PXooxW5rygbi49c.ttf` |
285
+ | Anton (display) | `1Ptgg87LROyAm0K08i4gS7lu` | `https://fonts.gstatic.com/s/anton/v27/1Ptgg87LROyAm0K08i4gS7lu.ttf` |
286
+ | Playfair Display (serif, variable) | `nuFiD-vYSZviVYUb_rj3ij__anPXPTvSgWE_-xU` | `https://fonts.gstatic.com/s/playfairdisplay/v40/nuFiD-vYSZviVYUb_rj3ij__anPXPTvSgWE_-xU.ttf` |
287
+
288
+ Variable fonts cover the full weight range (100–900) from a single URL — set `font.weight` on the clip. For a font not listed: copy an entry **verbatim** from the Studio SDK catalogue (~400 fonts) at <https://github.com/shotstack/shotstack-studio-sdk/blob/main/src/core/fonts/google-fonts.ts>, or open the font on <https://fonts.google.com>, view the CSS, and copy the exact `.ttf` URL from the `@font-face` `src`. Never hand-edit the version or hash segments.
270
289
 
271
290
  ### Usage example
272
291
 
@@ -297,7 +316,7 @@ The `font.family` value MUST match the `family` column in the table above (it's
297
316
  ## Top 5 mistakes
298
317
 
299
318
  1. **Reverse track order.** `tracks[0]` is the TOP layer, not the bottom. Captions go in early tracks; backgrounds go in late tracks.
300
- 2. **System fonts.** `Arial`, `Helvetica`, `Times New Roman`, etc. are not installed. Use Google Fonts via `timeline.fonts[]` (preferred) or one of the built-in fonts in `references/fonts.md`.
319
+ 2. **System fonts.** `Arial`, `Helvetica`, `Times New Roman`, etc. are not installed. Use Google Fonts via `timeline.fonts[]`, copied verbatim from the verified catalogue in the Fonts section.
301
320
  3. **Captions fill the whole frame.** A `rich-caption` clip without `width`, `height`, and `fit: "none"` covers the entire output. Use a named preset from `references/caption.md`.
302
321
  4. **`<text>` inside an SVG asset.** Raw `<text>` is unsupported. Use a `rich-text` asset for any text content; reserve SVG for shapes only.
303
322
  5. **Composing custom caption styles when presets exist.** The five named presets (Nico, Kai, Kapow, Lovely Little Lychee, Rizz) cover the common styles. Use one verbatim from `references/caption.md` unless the user asks for something specific.