Free now2sdk Core is completely free — no license key required   See what's included →
SDK Modules Docs Release Notes Pricing GitHub
Get the SDK →

LAnimation Reference Manual & Qt Integration Guide

The LAnimation class is a high-performance vector graphics and dynamic overlay engine built on top of the ThorVG rendering architecture. It is designed to load Adobe After Effects Lottie JSON files, render them as vector layers in memory, and publish them frame-by-frame to other targets (like LMixer or LPreview).

It supports multi-layered template loading, dynamic text replacements, shape color modifications, and frame-accurate playback control using markers.


1. API Reference & Key Methods

📌 Licensing

📌 Multi-Layer Lottie Operations

📌 Single-Layer Compatibility Overloads (Layer 0)

For backwards compatibility or simple single-layer templates, the following overloads default to layerId = 0:

📌 Video Format and Status


2. Markers Configuration & Lifecycle Management

Markers are critical for dividing a single Lottie template timeline into functional zones (e.g., Intro -> Loop -> Outro). Use addMarker to bind frame numbers to these states:

Marker Name Description Loop Behavior
"IN" Start Frame: The starting point of the animation. Defaults to frame 0.
"LOOP" Loop Start Anchor: When the animation reaches its end (totalFrames) or hitting a "STOP" marker, it wraps back to the "LOOP" frame instead of frame 0. Used to define the loop start point.
"STOP" Idle / Hold Frame: The boundary of the loop. If the animation reaches "STOP" and the layer is not in Out mode, it loops back to "LOOP". If "LOOP" is not set, it stops playing and freezes on this frame. Used to hold graphics on-air.
"OUT" Outro Start Frame: When stop(layerId) or close(layerId) is called, the playhead jumps directly to the "OUT" frame to play the exit animation. The layer automatically unloads at the end of the timeline. Triggers lower-third animations to exit.

3. Qt Integration Example

The following Qt implementation demonstrates how to manage lower-thirds and scoreboards on separate layers with dynamic text, color changes, and timing loops.

mainwindow.cpp

#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include "now2sdk.h"
#include <QColorDialog>
#include <QFileInfo>
#include <QCoreApplication>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent),
      ui(new Ui::MainWindow),
      m_lAnimation(new LAnimation()),
      m_lMixer(new LMixer()),
      m_lPreview(new LPreview()),
      m_gameTimer(new QTimer(this))
{
    ui->setupUi(this);

    // 1. Configure Formats
    videoFormatProps vFormat;
    vFormat.setVideoFormat = vF::HD1080_50p;
    m_lAnimation->setVideoFormat(vFormat);
    m_lMixer->setVideoFormat(vFormat);

    // 2. Add Animation to Composite Layout Mixer
    m_lMixer->addLayer("graphics_layer", m_lAnimation, 1, 0.0f, 0.0f, 255, 1920, 1080);

    // 3. Enable Preview Window
    m_lPreview->setProps("ui_framework", "qt");
    m_lPreview->previewEnable(ui->previewWidget, false, true);
    m_lPreview->previewObject(m_lMixer);

    // 4. Connect Signals for Real-Time Updating
    connect(ui->homeScoreSb, QOverload<int>::of(&QSpinBox::valueChanged), this, &MainWindow::updateScoreboard);
    connect(ui->guestScoreSb, QOverload<int>::of(&QSpinBox::valueChanged), this, &MainWindow::updateScoreboard);
    connect(ui->homeColorBtn, &QPushButton::clicked, this, &MainWindow::selectHomeColor);
    
    // Game Clock
    connect(m_gameTimer, &QTimer::timeout, this, &MainWindow::onClockTick);
}

MainWindow::~MainWindow() {
    m_lAnimation->stop(1); // Scoreboard Layer
    m_lAnimation->stop(2); // Lower Third Layer
    delete m_lPreview;
    delete m_lAnimation;
    delete m_lMixer;
    delete ui;
}

// ─── Scoreboard Layer (ID: 1) ───
void MainWindow::startScoreboard() {
    QString path = QCoreApplication::applicationDirPath() + "/template/scoreboard.json";
    
    if (m_lAnimation->loadTemplate(1, path.toStdString())) {
        m_lAnimation->play(1);
        updateScoreboard();
    }
}

void MainWindow::updateScoreboard() {
    // 1. Update text variables in the Lottie JSON
    m_lAnimation->update(1, "homeclub", ui->homeNameEdit->text().toStdString());
    m_lAnimation->update(1, "guestclub", ui->guestNameEdit->text().toStdString());
    m_lAnimation->update(1, "homescore", std::to_string(ui->homeScoreSb->value()));
    m_lAnimation->update(1, "guestscore", std::to_string(ui->guestScoreSb->value()));

    // 2. Update shapes colors inside the Lottie animation
    m_lAnimation->updateColor(1, "homeBG", m_homeColorHex.toStdString());
    m_lAnimation->updateColor(1, "guestBG", m_guestColorHex.toStdString());
}

void MainWindow::selectHomeColor() {
    QColor color = QColorDialog::getColor(Qt::red, this, "Select Home Team Color");
    if (color.isValid()) {
        m_homeColorHex = color.name(); // Format: #RRGGBB
        updateScoreboard();
    }
}

void MainWindow::onClockTick() {
    m_secondsElapsed++;
    int mins = m_secondsElapsed / 60;
    int secs = m_secondsElapsed % 60;
    QString timeStr = QString("%1:%2").arg(mins, 2, 10, QChar('0')).arg(secs, 2, 10, QChar('0'));
    
    // Inject real-time clock text to lower third layer
    m_lAnimation->update(1, "time", timeStr.toStdString());
}

// ─── Lower Third Layer (ID: 2) ───
void MainWindow::startLowerThird() {
    QString path = QCoreApplication::applicationDirPath() + "/template/lowerthird.json";
    
    if (m_lAnimation->loadTemplate(2, path.toStdString())) {
        // Set lifecycle markers: STOP at frame 30, OUT at frame 31
        m_lAnimation->addMarker(2, "STOP", 30);
        m_lAnimation->addMarker(2, "OUT", 31);
        
        m_lAnimation->update(2, "upText", "Alex Smith");
        m_lAnimation->update(2, "downText", "Match Referee");
        m_lAnimation->play(2);
    }
}

void MainWindow::hideLowerThird() {
    // Jumps playhead to frame 31 (OUT) to play the outro, then automatically unloads layer 2
    m_lAnimation->stop(2); 
}