Skip to content

Commit 34efb7b

Browse files
authored
Merge pull request #61 from shotstack/docs/html5-lottie-exports
Cover Lottie expressions, data files and export limits in the html5 guide
2 parents e48f533 + 8d5503a commit 34efb7b

2 files changed

Lines changed: 25 additions & 4 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ What you can build inside one `html5` clip, listed by the effect you'd reach for
9595
|---|---|---|
9696
| Particles, generative art | Canvas 2D drawn from `window.__shotstackSeek = (ms) => { … }` with seeded positions; or DOM dots with `physics2D` | Match |
9797
| 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 |
9999

100100
## Not available
101101

‎skills/shotstack/references/html5.md‎

Lines changed: 24 additions & 3 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; 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)
1515
- Sizing
1616
- 3D: what renders in preview and render
1717
- Worked example: animated lower-third (GSAP)
@@ -53,7 +53,7 @@ Four libraries and GSAP's plugins are always available — no `<script src=>` ta
5353
- **GSAP** (`window.gsap`) — primary animation library. Use timelines (`gsap.timeline()`) over loose tweens; the harness seeks timelines correctly.
5454
- **anime.js** (`window.anime`) — alternative animation library.
5555
- **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.
5757

5858
GSAP 3.15 plugins, already registered:
5959

@@ -94,7 +94,7 @@ Frames are captured by **seeking** the animation to each timestamp, not by playi
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.
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.
9898
- **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.
9999
- **No remote fonts** (`font-src 'self' data:`), except fonts you ingested (below). See *Fonts in HTML5*.
100100

@@ -145,6 +145,27 @@ FONT=$(shotstack ingest upload ./Brand.woff2 --watch --output json | tail -n1 |
145145

146146
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.
147147

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+
148169
## Sizing
149170

150171
The single most important rule: **size the clip to the content, not to the canvas.** Then position with `offset`.

0 commit comments

Comments
 (0)