> For the complete documentation index, see [llms.txt](https://docs.responsiveads.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.responsiveads.com/creating-ads/designing-your-ad-in-the-fluid-ad-creator/animation-timeline/using-sprite-sheets-and-animation-in-responsiveads.md).

# Using Sprite Sheets & Animation in ResponsiveAds

This page shows three reliable ways to deliver lightweight, transparent animations in HTML5 ads built with ResponsiveAds:

* **Animated WebP** (fastest path for simple loops)
* **Sprite sheets in Google Web Designer (GWD)** (visual authoring with a built‑in component)
* **Sprite sheets from TexturePacker** (professional packing + JSON metadata for custom/GSAP workflows)

> If your animation has transparency and must fit strict initial‑load limits (e.g., ≤150 KB), sprite sheets or animated WebP are typically the best choices.

***

### Picking the right approach

**Choose Animated WebP when…**

* You have a short, looping animation; one asset is easier to manage.
* You don’t need per‑frame interactivity.
* You’re fine providing a PNG fall‑back for older browsers.

**Choose Sprite Sheets (GWD or TexturePacker) when…**

* You want transparent overlays with tight file size control (trim + quantize).
* You need deterministic frame stepping, looping, or syncing with other timeline events.
* You may reuse frames across variants or export @2× assets.

***

### Prerequisites (for all workflows)

1. **Export a PNG sequence with alpha** from your motion tool (e.g., After Effects). Use sequential names: `walk_0001.png`, `walk_0002.png`, …
2. **Trim empty transparency** from each frame to reduce file size.
3. **Match target ad dimensions**, or plan to scale down.
4. Keep the animation concise (≤ 24 fps; short loops) to stay within initial‑load limits.

***

### Option A — Animated WebP (Ezgif)

**Best for:** fastest path to a single animated asset with transparency.

1. Convert your MOV with alpha **or** upload your **PNG sequence** to an online converter (e.g., Ezgif → Video to WebP / Animated WebP Maker).
2. Set frame delay and loop count; enable transparency.
3. **Optimize**: adjust quality/compression; consider reducing dimensions or dropping redundant frames.
4. Export your `.webp` and add a static PNG/GIF fall‑back for older browsers.

**Embed example**

```html
<picture>
  <source srcset="animation.webp" type="image/webp" />
  <img src="fallback.png" width="300" height="250" alt="Ad Animation" />
</picture>
```

**Tips**

* Aim for **≤150 KB initial load**. If over, reduce dimensions, frame count, or quality.
* Test transparency and looping in Chrome, Firefox, Safari, and Edge.
* Verify performance under network throttling (e.g., Fast 3G in DevTools).

***

### Option B — Sprite Sheets in Google Web Designer (GWD)

**Best for:** no‑code/low‑code authoring with a native Sprite Sheet component.

1. **Build the sprite sheet** from your PNG sequence (any packer or exporter). Keep total sheet size at or below **2048×2048** when possible.
2. In **GWD → Components → Sprite Sheet**, drag the component to the stage.
3. In **Properties**:
   * **Source**: your sprite sheet image (PNG‑32 with alpha).
   * **Frame Width / Height**: dimensions of a single cell.
   * **Number of Frames** and **Duration (ms)**.
   * **Loops**: `0` for infinite.
   * **Autoplay** if desired.
4. Preview to confirm alignment, then **Publish** (HTML5/AMPHTML as required).

**Optimization checklist**

* Use PNG compression (TinyPNG/ImageOptim) while preserving alpha.
* Split long animations into multiple sheets or lower resolution/frame count.
* Keep total initial load under your ad platform’s limit (commonly **≤150 KB**).

***

### Option C — TexturePacker → Sprite Sheets (Pro Workflow)

**Best for:** maximal packing efficiency, JSON metadata, custom code/GSAP control.

1. **Import PNG sequence** into TexturePacker.
2. Recommended settings for web ads:
   * **Trim Sprites**: remove excess transparency.
   * **Allow Rotation**: off (simplifies CSS/JS indexing).
   * **Max Size**: 1024–2048 px (pick the smallest that fits).
   * **Padding**: 1–2 px to prevent edge bleeding.
   * **Texture Format**: PNG‑32 (alpha preserved).
   * **Scale**: 0.5–0.75× if needed to hit size targets.
   * **Reduce Colors / PNGQuant / Zopfli** for smaller output.
3. **Export**: `animation.png` (sheet) + `animation.json` (metadata). Optionally export a second **@2×** sheet for retina.
4. **Integrate**:

**A) Quick CSS background‑position animation**

```html
<div id="sprite" style="width:120px;height:120px;background:url('animation.png') 0 0 no-repeat;"></div>
<script>
  const frames = 24, frameW = 120; let i = 0;
  setInterval(() => {
    i = (i + 1) % frames;
    document.getElementById('sprite').style.backgroundPosition = `${-i * frameW}px 0`;
  }, 1000 / 12); // 12 fps
</script>
```

**B) GSAP steps‑based animation**

```html
<div id="sprite" style="width:120px;height:120px;background:url('animation.png') 0 0 no-repeat;"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<script>
  const frames = 24, w = 120;
  gsap.to('#sprite', {
    backgroundPosition: `${-w * frames}px 0`,
    ease: `steps(${frames})`,
    duration: 1,
    repeat: -1
  });
</script>
```

**Pro tips**

* Keep frame rate ≤ 24 fps; shorter loops pack smaller.
* Reuse the same sheet across multiple ad sizes/variants where possible.
* For trimmed sprites, read the JSON’s per‑frame offsets when positioning.

***

### Option D — SVG Sprite Container + Timeline Trigger

**Best for:** authoring fades/overlays/impacts on a visual timeline while the **sprite playback** is controlled by code and starts **when the timeline plays**.

#### Overview

* The animated character/object lives inside an **SVG element**.
* A parent **sprite container** holds a single `<image>` that points to a packed **sprite sheet** (PNG with alpha) hosted in your **publish bucket**.
* The timeline manages opacity/position effects; a **start trigger** fires to begin integer frame‑stepping of the sheet. Optional pause/complete triggers stop/reset playback.

#### Build steps

1. **Prepare the sprite sheet** using Option B or C and upload it to a public path in your publish bucket.
2. **Create the SVG holder** sized to one frame. Place the full sheet as an `<image>` and reveal a single frame with a clipPath. Move the sheet by one frame width each tick.

```html
<svg id="spriteSvg" width="120" height="120" viewBox="0 0 120 120" role="img" aria-label="Sprite animation">
  <defs>
    <clipPath id="frameWindow"><rect width="120" height="120"/></clipPath>
  </defs>
  <g clip-path="url(#frameWindow)">
    <!-- Replace with your publish-bucket URL -->
    <image id="spriteSheet" href="https://cdn.yourdomain.com/ads/sprite.png"
           x="0" y="0" width="2880" height="120"/>
  </g>
</svg>
```

> Example: `width="2880"` implies **24 frames × 120px** (single‑row sheet).

3. **Playback controller** — listen for timeline events and step the sheet by whole frames.

```html
<script>
  (function(){
    const sheet = document.getElementById('spriteSheet');
    const FRAME_W = 120, FRAMES = 24, FPS = 12;
    let i = 0, timer = null;

    function step(){ i = (i + 1) % FRAMES; sheet.setAttribute('x', String(-i * FRAME_W)); }
    function play(){ if (!timer) timer = setInterval(step, 1000 / FPS); }
    function pause(){ if (timer) { clearInterval(timer); timer = null; } }
    function reset(){ i = 0; sheet.setAttribute('x', '0'); }

    // Timeline integration — dispatch these custom events from your timeline actions
    window.addEventListener('ra:timeline:start', play);
    window.addEventListener('ra:timeline:pause', pause);
    window.addEventListener('ra:timeline:complete', () => { pause(); reset(); });

    // Optional visibility‑based start
    const io = new IntersectionObserver(e=>{ if(e[0].isIntersecting) play(); }, {threshold: 0.5});
    io.observe(document.getElementById('spriteSvg'));
  })();
</script>
```

4. **Timeline triggers**

   * At **0 ms**: dispatch `ra:timeline:start`.
   * At a pause point: dispatch `ra:timeline:pause`.
   * At the end (after fade‑out): dispatch `ra:timeline:complete`.

   Example code for timeline actions:

   ```js
   // Start
   window.dispatchEvent(new Event('ra:timeline:start'))
   // Pause
   window.dispatchEvent(new Event('ra:timeline:pause'))
   // Complete
   window.dispatchEvent(new Event('ra:timeline:complete'))
   ```

#### Notes & gotchas

* For **multi‑row** sheets, compute `col = i % cols`, `row = Math.floor(i / cols)` and set both `x` and `y`.
* Add **1–2 px padding** between frames to prevent edge bleeding; snap to integer positions.
* You can replace `setInterval` with **GSAP** animating the `<image>` `x` property using `ease: steps(FRAMES)`.
* Keep animation logic isolated; the timeline continues to control fades/motion separately from sprite stepping.

***

### Testing & Compliance Checklist

* **Initial load**: ≤150 KB (GDN typical) — verify bundle + assets.
* **Transparency**: confirm in all target browsers.
* **Network**: test under Fast 3G to simulate real ad loads.
* **Fallbacks**: static backup image for non‑animated/unsupported cases.
* **Mobile**: check touch performance and layout.

***

### Troubleshooting

**Sprite offset/misalignment**

* Ensure each frame is the same width/height grid if using a simple sheet.
* If using trimmed frames + JSON, apply the per‑frame origin/offset when drawing.

**Edge bleeding/ghost lines**

* Add 1–2 px padding between cells.
* Snap background positions to whole pixels.

**File size too large**

* Reduce dimensions, quantize colors, drop redundant frames, lower fps.
* Split long loops into several shorter sheets or use WebP where appropriate.

**Stuttery playback**

* Use `steps(N)` easing (GSAP) or integer frame stepping.
* Avoid CSS transitions with fractional positions for frame indices.

***

### FAQ

**Do I need both WebP and a sprite sheet?**\
No. Pick one per creative. Use WebP for simplicity; sprite sheets for control/reuse.

**What about retina?**\
Export @2× sheets and scale CSS/JS positions accordingly, or serve based on DPR.

**Will this work in AMPHTML?**\
Yes—with constraints. Prefer GWD export for AMP creatives, and mind inline script limits.

**How do I count frames?**\
In TexturePacker/GWD you set the frame count explicitly; with WebP the timing is encoded in the asset.

***

### Deliverables to Engineering

* **Animated WebP**: `animation.webp` (+ `fallback.png`), width × height, loop rules, target KB.
* **GWD Sprite Sheet**: packed PNG sheet, frame dimensions, frame count, duration, loop policy, published bundle.
* **TexturePacker Sprite Sheet**: PNG + JSON, intended fps, any offsets, example integration (CSS/GSAP).
