# Component inputs

inputDefs are static inspector values. Asset inputs store IDs on the clip and resolve to playback URLs or VidovaClipData before they reach the class.

`inputDefs` are static values on the clip. The inspector sets them. They do not tween. Animation still lives in generators and class signals. See [Animation](/docs/custom-elements/animation).

## Types

| `type` | Clip value | Class signal |
| --- | --- | --- |
| `string` | string | `SimpleSignal<string, this>` |
| `number` | number | `SimpleSignal<number, this>` |
| `boolean` | boolean | `SimpleSignal<boolean, this>` |
| `color` | hex string | `ColorSignal<this>` with `@colorSignal` |
| `enum` | one of `options` | `SimpleSignal<string, this>` |
| `font` | family string | `SimpleSignal<string, this>` |
| `asset` | **asset ID** on the clip | playback URL string, or `VidovaClipData` |

Each def needs `name`, `type`, and `default`. `label` is optional. `enum` needs `options`. `asset` needs `assetTypes`.

## Asset contract

The clip stores an asset UUID in `inputs` and in `inputDefs.default`. At preview and render, Vidova replaces that ID before the class constructor runs.

| `assetTypes` | Runtime prop |
| --- | --- |
| `['image']` | playback URL string |
| `['video']` | playback URL string |
| `['audio']` | playback URL string |
| `['model3d']` | playback URL string |
| `['vidova']` | `VidovaClipData` object |

Do not mix kinds on one input. An image slot is `assetTypes: ['image']` only.

The class signal for a URL asset **must** use `@initial('')`. Never put the UUID in `@initial`. `inputDefs.default` may be an asset ID. `@initial` must not.

```tsx
@initial('')
@signal()
public declare readonly image: SimpleSignal<string, this>;
```

Pass that signal to the media node with explicit size:

```tsx
<Img
  src={() => this.image()}
  width={() => this.frameWidth()}
  height={() => this.frameHeight()}
/>
```

Empty string is a no-op. A UUID is not a URL. `<Img>` will refuse it.

For screen recordings:

```tsx
import { ScreenRecording, FaceCamera, type VidovaClipData } from '@vidova/components';

@initial(undefined)
@signal()
public declare readonly screen: SimpleSignal<VidovaClipData | undefined, this>;
```

Use fields on `this.screen()` (`screenSrc`, `cameraSrc`, cursor arrays). Do not pass the whole object to `<Video src>`.

## Timeline

After [component](/docs/mcp/tools/component) `create` or `edit`, place **one** clip:

```
timeline_edit addClip
  type: component
  assetId: <component asset id>
  componentInputs: { image: "<image asset id>" }
```

Do not add a parallel `type: image` or `type: video` clip for the same file. The component input **is** the media. A leftover still on the timeline means the shader never ran.

`componentInputs` overrides `inputDefs.default`. Both store asset IDs, not URLs.

## Example

```json
[
  {
    "name": "image",
    "type": "asset",
    "default": "",
    "label": "Image",
    "assetTypes": ["image"]
  },
  {
    "name": "refraction",
    "type": "number",
    "default": 0.04,
    "label": "Refraction"
  }
]
```

`refraction` is a static knob. If it should move over time, keep a class signal and tween it in `animate()` instead of expecting the input to change.

Shaders that sample this image: [Shaders](/docs/custom-elements/shaders).
