Skip to content

Commit 46d1377

Browse files
authored
Merge pull request #53 from shotstack/docs/html5-ingest-files
[2/3] Use ingested images and fonts in html5 pages
2 parents dfe1b2f + 52988a9 commit 46d1377

6 files changed

Lines changed: 52 additions & 12 deletions

File tree

‎skills/shotstack/SKILL.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ SRC=$(shotstack ingest upload ./clip.mp4 --watch --output json | tail -n1 | jq -
9090
# …then reference "$SRC" as an asset.src in your Edit JSON and run `shotstack render`.
9191
```
9292

93+
This includes images and fonts for an `html5` page: put the URL in its `html` or `css`.
94+
9395
The bare command (no `--watch`) returns only an `id`; the hosted `source` URL does not exist until ingestion is `ready`. Always `--watch` (or follow up with `shotstack ingest status <id> --watch`) when you need the URL.
9496

9597
Other ingest subcommands: `ingest fetch <url>` (host a copy of a remote URL), `ingest status <id>`, `ingest list`, `ingest delete <id>`. **Read [`references/ingest.md`](references/ingest.md) for the full upload→render workflow, status values, and supported file types.**

‎skills/shotstack/references/html5-effects.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ What you can build inside one `html5` clip, listed by the effect you'd reach for
102102
- **WebGL, shaders, 3D models:** use CSS 2.5D and SVG filters.
103103
- **Video or audio inside the clip:** put footage and sound on other timeline tracks; `html5` is the graphics layer.
104104
- **Scroll, drag or pointer-driven animation:** capture is time-driven only.
105-
- **Remote fonts, images, scripts:** inline them as `data:` URIs.
105+
- **Remote scripts, and images or fonts you haven't ingested:** inline them as `data:` URIs. Images and fonts you ingested work by URL; see [`html5.md`](html5.md).
106106

107107
## Cost
108108

‎skills/shotstack/references/html5-snippets.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ Read [`html5.md`](html5.md) for the rules these obey. The non-negotiables:
1616
- **Size the clip to the content, not the canvas.** `html, body` pinned to the clip's `width`/`height`; place with `offset` (`{x:0,y:0}` is centred, `y` positive is up). Use **px**, never `vw`/`vh`/`%`.
1717
- **The body is transparent by default** — the clip composites over the layers below (only set an opaque background if you want one).
1818
- **Canvas only from the seek hook.** Draw canvas 2D inside `window.__shotstackSeek(ms)`, never in a `requestAnimationFrame` loop. WebGL is blank in the cloud render. SVG or positioned DOM is usually lighter.
19-
- **No network.** gsap (with its plugins), anime, d3 and lottie are preloaded; external `<script src>`, `fetch`, remote `<img>`, and remote fonts are all CSP-blocked — inline everything as `data:` URIs.
20-
- **Fonts:** `timeline.fonts[]` does **not** reach `html5` and remote `@font-face` is blocked. These snippets name a display font first but render in the `system-ui` fallback unless you inline the font as a `data:` `@font-face`.
19+
- **No network.** gsap (with its plugins), anime, d3 and lottie are preloaded; external `<script src>`, `fetch`, remote `<img>`, and remote fonts are all CSP-blocked. Inline them as `data:` URIs, or use the URL of an image or font you ingested (see [`html5.md`](html5.md)).
20+
- **Fonts:** `timeline.fonts[]` does **not** reach `html5` and remote `@font-face` is blocked. These snippets name a display font first but render in the `system-ui` fallback unless you load the font, from an ingested font's URL or a `data:` `@font-face`.
2121
- **Use unique element IDs for GSAP targets, not `:nth-child` or compound CSS selectors.** Studio preview doesn't resolve `.parent:nth-child(n) .child` patterns; `#id` works everywhere. When animating repeated elements (list rows, bars, cards), generate a unique ID per item (`id="row0"`, `id="bar0"`) rather than relying on structural selectors.
2222

2323
Coordinates below assume a **1080×1920 vertical** canvas; adjust `offset` for other sizes.
@@ -48,7 +48,7 @@ The reference entrance: opacity, blur and a 16 px rise settle **together** off o
4848
}
4949
```
5050

51-
`base` (0.6 s) entrance on `power3.out`, then a `hold` (1.5 s) settle. Swap `{{title}}` via top-level `merge[]`. `Clash Display` falls back to `system-ui` unless you inline it as a `data:` `@font-face` (see Fonts above).
51+
`base` (0.6 s) entrance on `power3.out`, then a `hold` (1.5 s) settle. Swap `{{title}}` via top-level `merge[]`. `Clash Display` falls back to `system-ui` unless you load it, from an ingested font's URL or a `data:` `@font-face` (see Fonts above).
5252

5353
---
5454

‎skills/shotstack/references/html5.md‎

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ This is the **modern replacement for the deprecated `html` asset.** `html5` runs
1111
- Required and optional fields
1212
- Preloaded libraries
1313
- The browser harness (deterministic auto-seek)
14-
- Sandbox restrictions: no network, inline everything (incl. fonts)
14+
- Sandbox restrictions: no network; ingested images and fonts by URL, everything else inline
1515
- Sizing
1616
- 3D: what renders in preview and render
1717
- Worked example: animated lower-third (GSAP)
@@ -89,25 +89,56 @@ Frames are captured by **seeking** the animation to each timestamp, not by playi
8989

9090
**Duration comes from the clip's `length`** — there's no animation-duration auto-detection. Size your animation to run within (or fill) the clip's `length`.
9191

92-
## Sandbox restrictions: no network, inline everything
92+
## Sandbox restrictions: no network, ingested files by URL
9393

9494
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:
9595

9696
- **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.
9797
- **No `fetch` / `XMLHttpRequest`** (`connect-src 'none'`). Bundle any data inline — e.g. the JS array in the bar-chart example.
98-
- **No remote images** (`img-src 'self' data: blob:`). Embed images as `data:` URIs. A `data:image/svg+xml` background is fine.
99-
- **No remote fonts** (`font-src 'self' data:`) — see below.
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+
- **No remote fonts** (`font-src 'self' data:`), except fonts you ingested (below). See *Fonts in HTML5*.
100+
101+
### Images and fonts you ingested
102+
103+
Reference an ingested image or font by its `source` URL, straight from `html` or `css`: an `<img src>`, a CSS `url()` or an `@font-face` `src`. Before capture the renderer fetches each file and inlines it, so the page itself still makes no request.
104+
105+
<!-- surface:cli -->
106+
Upload with `shotstack ingest upload`, or host a copy of a URL with `shotstack ingest fetch`:
107+
108+
```sh
109+
PHOTO=$(shotstack ingest upload ./hero.jpg --watch --output json | tail -n1 | jq -r .source)
110+
FONT=$(shotstack ingest upload ./Brand.woff2 --watch --output json | tail -n1 | jq -r .source)
111+
```
112+
<!-- /surface -->
113+
114+
```css
115+
@font-face { font-family: 'Brand'; src: url(<FONT>) format('woff2'); }
116+
.hero { background: url(<PHOTO>) center / cover; }
117+
```
118+
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+
- **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+
- **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+
- **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+
- **Studio's preview doesn't load ingested files yet**, so they show as missing there. The render is unaffected.
124+
<!-- surface:cli -->
125+
- Until Studio supports them, check the page with `shotstack render <file> --env stage --watch`.
126+
<!-- /surface -->
100127

101128
### Fonts in HTML5
102129

103-
`timeline.fonts[]` does **not** apply to `html5` assets (it loads fonts for `rich-text` / `rich-caption` only), and a remote `@font-face` URL (Google Fonts, etc.) is CSP-blocked. Two ways to get a custom font into an `html5` clip:
130+
`timeline.fonts[]` does **not** apply to `html5` assets (it loads fonts for `rich-text` / `rich-caption` only), and a remote `@font-face` URL (Google Fonts, etc.) is CSP-blocked. Three ways to get a custom font into an `html5` clip:
104131

105-
1. **Inline it as a `data:` `@font-face`** — base64-encode the `.woff2` / `.ttf`:
132+
1. **Ingest it and use its URL** (see *Images and fonts you ingested*).
133+
<!-- surface:cli -->
134+
For a Google Font, `shotstack ingest fetch` the font file's `fonts.gstatic.com` URL and use the hosted copy.
135+
<!-- /surface -->
136+
2. **Inline it as a `data:` `@font-face`** — base64-encode the `.woff2` / `.ttf`:
106137
```css
107138
@font-face { font-family: 'Brand'; src: url('data:font/woff2;base64,<…>') format('woff2'); }
108139
.title { font-family: 'Brand', sans-serif; }
109140
```
110-
2. **Use a system family** (`system-ui`, `Arial`, `Georgia`, …) — resolves with no load, but each machine picks its own font, so text in Studio's preview won't match the cloud render exactly. Embed a font whenever the text must match.
141+
3. **Use a system family** (`system-ui`, `Arial`, `Georgia`, …) — resolves with no load, but each machine picks its own font, so text in Studio's preview won't match the cloud render exactly. Embed a font whenever the text must match.
111142

112143
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.
113144

‎skills/shotstack/references/ingest.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ shotstack studio edit.json
7878
Remember `tracks[0]` is the **top** layer (see `shared/agent-core.md`), so the
7979
logo track sits above the video.
8080

81+
## Images and fonts in an html5 page
82+
83+
An `html5` page can use images and fonts you ingested by putting their
84+
`source` URLs in its `html` or `css` (`<img src>`, CSS `url()`, `@font-face`).
85+
The file must belong to the same account and environment as the render. Limits
86+
and details are in [`html5.md`](html5.md).
87+
8188
## Fetch a remote URL instead of uploading
8289

8390
If the media is already at a URL but you want Shotstack to host its own copy

‎skills/shotstack/shared/agent-core.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ Use only the **current** asset types; the deprecated ones still parse but should
232232
| `audio` | Audio clip placed at a specific time on the timeline, or AI-generated speech or music from a `prompt`. |
233233
| `rich-text` | Styled text overlay with full typography control. **Use this instead of `text`/`html`/`title`.** |
234234
| `svg` | Vector graphics from raw SVG markup: `src` starts with `<svg`, never a URL or `data:` URI (the render fails). See **`svg` assets** below. |
235-
| `html5` | Self-contained HTML/CSS/JS page rendered in an iframe (motion graphics, charts, animated overlays). Preloads gsap with its plugins (SplitText, DrawSVG, MorphSVG, MotionPath, Flip and more), d3, anime and lottie. See `references/html5.md`. **Never use the deprecated `html` asset.** |
235+
| `html5` | Self-contained HTML/CSS/JS page rendered in an iframe (motion graphics, charts, animated overlays). Preloads gsap with its plugins (SplitText, DrawSVG, MorphSVG, MotionPath, Flip and more), d3, anime and lottie. Images and fonts: the URL of a file you ingested, or a `data:` URI; other remote URLs are blocked. See `references/html5.md`. **Never use the deprecated `html` asset.** |
236236
| `rich-caption` | Word-level animated captions sourced from audio, video, or subtitle files. See `references/caption.md`. |
237237
| `luma` | Luma matte for masking effects. |
238238

0 commit comments

Comments
 (0)