Docs

Custom element quickstart

Write a Node subclass with @vidova/2d, implement animateIn and animate, then place it with component create and timeline_edit addClip.

View as Markdown

This path assumes Vidova is running, Local MCP is on, and a project is open in the editor. Install steps are on the MCP overview.

1. Write the class

The exported class name must match componentName. animate() is the timeline entry point. animateIn() is the intro.

import { Node, NodeProps, Txt, signal, initial, colorSignal } from '@vidova/2d';
import {
  SignalValue,
  SimpleSignal,
  ColorSignal,
  PossibleColor,
  easeOutCubic,
  type ThreadGenerator,
} from '@vidova/core';
 
export interface HelloTitleProps extends NodeProps {
  label?: SignalValue<string>;
  textColor?: SignalValue<PossibleColor>;
  textSize?: SignalValue<number>;
}
 
export class HelloTitle extends Node {
  @initial('Hello')
  @signal()
  public declare readonly label: SimpleSignal<string, this>;
 
  @initial('#ffffff')
  @colorSignal()
  public declare readonly textColor: ColorSignal<this>;
 
  @initial(48)
  @signal()
  public declare readonly textSize: SimpleSignal<number, this>;
 
  public constructor(props?: HelloTitleProps) {
    super({ ...props });
    this.add(
      <Txt
        text={() => this.label()}
        fill={() => this.textColor()}
        fontSize={() => this.textSize()}
        fontFamily="Inter Variable"
        fontWeight={600}
      />,
    );
  }
 
  public *animateIn(duration: number = 0.4): ThreadGenerator {
    this.opacity(0);
    yield* this.opacity(1, duration, easeOutCubic);
  }
 
  public *animate(duration?: number): ThreadGenerator {
    yield* this.animateIn(duration ?? 0.4);
  }
}

Use the exact fontFamily string. Inter Variable is the default UI font. Code text uses Fira Code Variable.

2. Create the asset

Call component with action create:

{
  "action": "create",
  "name": "Hello title",
  "componentName": "HelloTitle",
  "code": "<the TSX above>"
}

The result includes assetId. If the tool reports FAILED TO RENDER, fix the class before you place it.

3. Place it on the timeline

Call timeline_edit with action addClip, type component, and that assetId. Never type=text.

4. Capture a preview

Call preview with action captureFrame at a timecode where the clip is visible. Confirm the text is on screen and fully inside the frame.

A catalog template is faster when one already covers the design. Use createFromTemplate instead of create. Full props and methods: Authoring.