# Custom elements

A custom element is a TSX class that extends Node. It compiles into a component asset and plays on a type=component clip.

A custom element is a TSX class that extends `Node`, or a closer built-in such as `Txt` or `Layout`. The class compiles into a component asset. The timeline plays it on a clip with `type` `component`.

JSX creates real nodes immediately. It is not React.

Prefer a catalog template when one already covers the design. Call [component](/docs/mcp/tools/component) with `action` `createFromTemplate`, then place the returned `assetId` with [timeline_edit](/docs/mcp/tools/timeline_edit) `addClip`. Write a class from scratch only when no template fits.

## Packages

Import from these three packages only:

| Package | Role |
| --- | --- |
| `@vidova/2d` | Nodes, JSX, `@signal` / `@initial` / `@colorSignal` |
| `@vidova/core` | Signals, generators, tweens, refs, easing |
| `@vidova/components` | Built-in scene nodes such as `ScreenRecording` and `FaceCamera` |

Details: [Packages](/docs/custom-elements/packages).

## Timeline contract

The exported class name is `componentName`. `animate()` is the method the timeline calls. `animateIn()` is the intro. Keep them separate. Layout and naming rules that fail at render: [Layout](/docs/custom-elements/layout).

The editor must be open. A create or edit that reports `FAILED TO RENDER` is a broken element. Fix it before you place the clip.

Asset inputs (`type: asset`) let a component take an image, video, audio, 3D model, or screen recording. The clip stores the asset ID. At preview the class receives a playback URL or a `VidovaClipData` object. [Inputs](/docs/custom-elements/inputs).

Shaders are SkSL on a cached node, not GLSL. [Shaders](/docs/custom-elements/shaders).

## Next

- [Quickstart](/docs/custom-elements/quickstart): smallest working class, then place it
- [Packages](/docs/custom-elements/packages): `@vidova/2d`, `@vidova/core`, `@vidova/components`
- [Authoring](/docs/custom-elements/authoring): props, constructor, methods
- [Inputs](/docs/custom-elements/inputs): `inputDefs`, asset inputs, `componentInputs`
- [Signals](/docs/custom-elements/signals): reactive props
- [Layout](/docs/custom-elements/layout): flex, `layout={false}`, naming
- [Shaders](/docs/custom-elements/shaders): SkSL, `cache`, `withCommonShader`
- [Animation](/docs/custom-elements/animation): generators, `animate` vs `animateIn`
