> ## Documentation Index
> Fetch the complete documentation index at: https://docs.motioness.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Web component

Drop-in <motioness-img> custom element with no build step required.

# Web component

`<motioness-img>` is a self-contained custom element. Works in any HTML page, no framework or bundler needed.

## Install

Either import from npm:

```bash
npm install @motioness/proxy-client
```

```ts
import '@motioness/proxy-client/element';
```

Or use the prebuilt CDN script:

```html
<script type="module" src="https://motioness.com/proxy-client/element.js"></script>
```

The element registers itself on import.

## Basic use

```html
<motioness-img
  project-key="pk_abc"
  src="https://cdn.acme.com/hero.png"
></motioness-img>
```

That's it. The element renders an internal `<video>` with the proxy mp4, poster jpg, and `autoplay muted loop playsinline` defaults. You'll get a square aspect (matching the source) at the element's natural width.

## Attributes

| Attribute | Description |
|---|---|
| `project-key` | Required. Your `pk_…`. |
| `src` | Required. Full source URL with scheme. |
| `motion` | `subtle` / `medium` / `kinetic` |
| `mode` | `loop` / `animate-in` / `animate-on-hover` |
| `dur-seconds` | Output length, 2-8 |
| `prompt` | Override prompt (≤500 chars) |
| `seed` | Deterministic seed |
| `aspect` | `1:1` / `16:9` / `9:16` / `preserve` |
| `idempotency-key` | Force distinct asset from same source |
| `wait-ms` | Long-poll deadline, 0-10000 |
| `signature` | HMAC for signed mode |
| `exp` | Unix seconds expiry for signed mode |
| `loading` | `lazy` defers mp4 load until in viewport |
| `origin` | Override proxy origin (default `https://motioness.com`) |

## Modes

```html
<!-- Loops forever -->
<motioness-img project-key="pk_..." src="..." mode="loop" />

<!-- Plays once on mount -->
<motioness-img project-key="pk_..." src="..." mode="animate-in" />

<!-- Pauses until hover -->
<motioness-img project-key="pk_..." src="..." mode="animate-on-hover" />
```

`animate-on-hover` resets to the first frame on `mouseleave`, so leaving + re-entering replays from the start.

## Styling

The element renders a `<video>` internally. Use standard CSS:

```html
<motioness-img
  project-key="pk_abc"
  src="..."
  style="
    width: 100%;
    max-width: 800px;
    aspect-ratio: 16/9;
    border-radius: 16px;
    overflow: hidden;
  "
/>
```

To target the inner `<video>` specifically:

```css
motioness-img::part(video) {
  object-fit: cover;
}
```

## Events

```ts
const el = document.querySelector('motioness-img')!;

el.addEventListener('motioness-ready', (e) => {
  console.log('mp4 loaded', (e as CustomEvent).detail);
});

el.addEventListener('motioness-error', (e) => {
  console.error((e as CustomEvent).detail);
});
```

## Programmatic update

The element observes attribute changes — set new attributes and the URL rebuilds.

```ts
const el = document.querySelector('motioness-img')!;
el.setAttribute('motion', 'kinetic');
el.setAttribute('seed', '42');
// New URL is constructed; <video> reloads
```

## Server rendering

The element progressively enhances. SSR'd HTML works — when the script loads, it upgrades. Until then the element is invisible (the custom element CSS sets `display: block` on upgrade).

For a fallback while the script is in flight:

```html
<motioness-img project-key="pk_abc" src="..." style="aspect-ratio: 16/9; background: #111">
  <img slot="fallback" src="..." alt="..." style="width: 100%" />
</motioness-img>
```

(The `slot="fallback"` content is replaced once the element upgrades.)