Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
efc35e3
Add initial Lottie export support
pgilfernandez Jun 2, 2026
30a637a
Add Lottie preview action
pgilfernandez Jun 2, 2026
a260958
Add Lottie path shape support
pgilfernandez Jun 2, 2026
289d941
Add Lottie group parenting support
pgilfernandez Jun 2, 2026
1155803
Add Lottie sub-path trim support
pgilfernandez Jun 2, 2026
f48a88e
Add native Lottie text layers
pgilfernandez Jun 2, 2026
d8291d6
Preserve Friction layer order in Lottie
pgilfernandez Jun 2, 2026
77fd4d4
Add Lottie dash path effect support
pgilfernandez Jun 3, 2026
e4201a7
Animate Lottie fill and stroke paint
pgilfernandez Jun 3, 2026
cf50d73
Add Lottie gradient paint support
pgilfernandez Jun 3, 2026
f80b209
Compact sampled Lottie keyframes
pgilfernandez Jun 3, 2026
775f86f
Minify Lottie output and linearize compact keyframes
pgilfernandez Jun 3, 2026
e222162
Optimize Lottie JSON output
pgilfernandez Jun 3, 2026
533cedc
Omit empty Lottie root metadata
pgilfernandez Jun 3, 2026
3b157c3
Export Lottie transform keyframes from Friction keys
pgilfernandez Jun 3, 2026
9c93082
Export Lottie paint keyframes from Friction keys
pgilfernandez Jun 3, 2026
39699b5
Export Lottie gradient keyframes from Friction keys
pgilfernandez Jun 3, 2026
6802a8b
Export Lottie path effect keyframes from Friction keys
pgilfernandez Jun 3, 2026
c00dc76
Animate Lottie rectangle geometry
pgilfernandez Jun 3, 2026
e220de6
Add controls to Lottie preview
pgilfernandez Jun 3, 2026
fb5ae21
Add Lottie image asset export
pgilfernandez Jun 3, 2026
a902b85
Add Lottie blend mode export
pgilfernandez Jun 3, 2026
f3f29f0
Add Lottie preview renderer selector
pgilfernandez Jun 3, 2026
4e28d21
Add optional Lottie SVG renderer fix
pgilfernandez Jun 3, 2026
e71ed66
Add Lottie alpha matte export
pgilfernandez Jun 4, 2026
f67c087
Support grouped Lottie alpha mattes
pgilfernandez Jun 4, 2026
1ce5aa9
Improve Lottie text export options
pgilfernandez Jun 4, 2026
409d8b9
tooltip improvement
pgilfernandez Jun 4, 2026
6671004
Animate compatible Lottie paths
pgilfernandez Jun 5, 2026
8f98117
Optimize animated Lottie path keyframes
pgilfernandez Jun 5, 2026
3dc93fd
Fix linked Lottie image preview paths
pgilfernandez Jun 5, 2026
fb3ed26
Toggle Lottie preview playback on click
pgilfernandez Jun 5, 2026
69b0dcf
Add Lottie preview background selector
pgilfernandez Jun 5, 2026
24df37d
Apply SVG renderer fix only in Lottie preview
pgilfernandez Jun 5, 2026
e8c1fbc
Update Lottie export dialog info
pgilfernandez Jun 5, 2026
25727f6
Redesign Lottie preview player controls
pgilfernandez Jun 6, 2026
54a52f2
Add default Lottie preview background option
pgilfernandez Jun 6, 2026
1367775
Normalize Lottie preview frame timeline
pgilfernandez Jun 6, 2026
ca26a91
Show Lottie preview project info
pgilfernandez Jun 8, 2026
84a314f
Add dotLottie export support
pgilfernandez Jun 8, 2026
006d642
Add dotLottie preview player
pgilfernandez Jun 8, 2026
59d0691
Reorganize Lottie export options
pgilfernandez Jun 9, 2026
ce558a4
Auto-hide Lottie preview controls
pgilfernandez Jun 9, 2026
1fe6bcc
Skip hidden objects in Lottie exports
pgilfernandez Jun 9, 2026
35b3c70
Export unanimated Lottie paths as static
pgilfernandez Jun 12, 2026
a1092b2
Export Lottie groups as precompositions
pgilfernandez Jun 14, 2026
1e0542e
Export Lottie parent effects
pgilfernandez Jun 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/app/GUI/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
#include "GUI/edialogs.h"
#include "eimporters.h"
#include "dialogs/exportsvgdialog.h"
#include "dialogs/exportlottiedialog.h"
#include "widgets/alignwidget.h"
#include "widgets/welcomedialog.h"
#include "Boxes/textbox.h"
Expand Down Expand Up @@ -107,6 +108,8 @@ MainWindow::MainWindow(Document& document,
, mSaveBackAct(nullptr)
, mPreviewSVGAct(nullptr)
, mExportSVGAct(nullptr)
, mPreviewLottieAct(nullptr)
, mExportLottieAct(nullptr)
, mRenderVideoAct(nullptr)
, mCloseProjectAct(nullptr)
, mLinkedAct(nullptr)
Expand Down Expand Up @@ -424,6 +427,8 @@ void MainWindow::updateSettingsForCurrentCanvas(Canvas* const scene)

if (mPreviewSVGAct) { mPreviewSVGAct->setEnabled(scene); }
if (mExportSVGAct) { mExportSVGAct->setEnabled(scene); }
if (mPreviewLottieAct) { mPreviewLottieAct->setEnabled(scene); }
if (mExportLottieAct) { mExportLottieAct->setEnabled(scene); }
if (mSaveAct) { mSaveAct->setEnabled(scene); }
if (mSaveAsAct) { mSaveAsAct->setEnabled(scene); }
if (mSaveBackAct) { mSaveBackAct->setEnabled(scene); }
Expand Down Expand Up @@ -1210,6 +1215,27 @@ void MainWindow::exportSVG(const bool &preview)
}
}

const QString MainWindow::checkBeforeExportLottie()
{
return tr("Lottie export is currently an initial native exporter. "
"It writes composition timing, canvas size, background, and "
"keeps scene layers isolated for future vector mapping.");
}

void MainWindow::exportLottie(const bool &preview)
{
const auto dialog = new ExportLottieDialog(this,
preview ? QString() : checkBeforeExportLottie());
dialog->setAttribute(Qt::WA_DeleteOnClose);
connect(dialog, &ExportLottieDialog::formatChanged,
this, &MainWindow::updatePreviewLottieAction);
if (!preview) {
dialog->show();
} else {
dialog->showPreview(true /* close when done */);
}
}

void MainWindow::updateLastOpenDir(const QString &path)
{
if (path.isEmpty()) { return; }
Expand Down
5 changes: 5 additions & 0 deletions src/app/GUI/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ class MainWindow : public QMainWindow
void saveBackup();
const QString checkBeforeExportSVG();
void exportSVG(const bool &preview = false);
const QString checkBeforeExportLottie();
void exportLottie(const bool &preview = false);
void updateLastOpenDir(const QString &path);
void updateLastSaveDir(const QString &path);
const QString getLastOpenDir();
Expand Down Expand Up @@ -219,6 +221,7 @@ class MainWindow : public QMainWindow
static MainWindow *sInstance;

void updateRecentMenu();
void updatePreviewLottieAction(const QString& format = QString());

void addRecentFile(const QString &recent);
void readRecentFiles();
Expand All @@ -243,6 +246,8 @@ class MainWindow : public QMainWindow
QAction *mSaveBackAct;
QAction *mPreviewSVGAct;
QAction *mExportSVGAct;
QAction *mPreviewLottieAct;
QAction *mExportLottieAct;
QAction *mRenderVideoAct;
QAction *mCloseProjectAct;
QAction *mLinkedAct;
Expand Down
46 changes: 46 additions & 0 deletions src/app/GUI/menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,25 @@

using namespace Friction;

void MainWindow::updatePreviewLottieAction(const QString& format)
{
if (!mPreviewLottieAct) { return; }

const QString currentFormat = format.isEmpty() ?
AppSupport::getSettings("exportLottie", "format", "json").toString() :
format;
const bool dotLottie = currentFormat == QStringLiteral("lottie");
const QString text = dotLottie ?
tr("Preview dotLottie", "MenuBar_File") :
tr("Preview Lottie", "MenuBar_File");
const QString toolTip = dotLottie ?
tr("Preview dotLottie Animation in Web Browser") :
tr("Preview Lottie Animation in Web Browser");
mPreviewLottieAct->setText(text);
mPreviewLottieAct->setToolTip(toolTip);
mPreviewLottieAct->setData(toolTip);
}

void MainWindow::setupMenuBar()
{
mMenuBar = new QMenuBar(nullptr);
Expand Down Expand Up @@ -144,6 +163,31 @@ void MainWindow::setupMenuBar()
mExportSVGAct->setObjectName("ExportSVGAct");
cmdAddAction(mExportSVGAct);

mPreviewLottieAct = mFileMenu->addAction(QIcon::fromTheme("seq_preview"),
tr("Preview Lottie", "MenuBar_File"),
this, [this]{ exportLottie(true); },
QKeySequence(AppSupport::getSettings("shortcuts",
"previewLottie",
"Alt+Ctrl+F12").toString()));
mPreviewLottieAct->setEnabled(false);
mPreviewLottieAct->setToolTip(tr("Preview Lottie Animation in Web Browser"));
mPreviewLottieAct->setData(mPreviewLottieAct->toolTip());
mPreviewLottieAct->setObjectName("PreviewLottieAct");
cmdAddAction(mPreviewLottieAct);
updatePreviewLottieAction();

mExportLottieAct = mFileMenu->addAction(QIcon::fromTheme("output"),
tr("Export Lottie", "MenuBar_File"),
this, &MainWindow::exportLottie,
QKeySequence(AppSupport::getSettings("shortcuts",
"exportLottie",
"Alt+Shift+F12").toString()));
mExportLottieAct->setEnabled(false);
mExportLottieAct->setToolTip(tr("Export Lottie Animation"));
mExportLottieAct->setData(mExportLottieAct->toolTip());
mExportLottieAct->setObjectName("ExportLottieAct");
cmdAddAction(mExportLottieAct);

mFileMenu->addSeparator();
mCloseProjectAct = mFileMenu->addAction(QIcon::fromTheme("dialog-cancel"),
tr("Close", "MenuBar_File"),
Expand Down Expand Up @@ -844,6 +888,8 @@ void MainWindow::setupMenuBar()

mToolbar->addAction(mPreviewSVGAct);
mToolbar->addAction(mExportSVGAct);
mToolbar->addAction(mPreviewLottieAct);
mToolbar->addAction(mExportLottieAct);
mToolbar->updateActions();

setMenuBar(mMenuBar);
Expand Down
15 changes: 15 additions & 0 deletions src/core/Boxes/imagebox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,21 @@ void ImageBox::setFilePath(const QString &path) {
rename(QFileInfo(path).completeBaseName());
}

QString ImageBox::filePath() const
{
return mFileHandler.path();
}

bool ImageBox::hasImage() const
{
return mFileHandler && mFileHandler->hasImage();
}

sk_sp<SkImage> ImageBox::image() const
{
return mFileHandler ? mFileHandler->getImage() : nullptr;
}

void ImageBox::reload() {
if(mFileHandler) mFileHandler->reloadAction();
}
Expand Down
3 changes: 3 additions & 0 deletions src/core/Boxes/imagebox.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ class CORE_EXPORT ImageBox : public BoundingBox {

void changeSourceFile();
void setFilePath(const QString &path);
QString filePath() const;
bool hasImage() const;
sk_sp<SkImage> image() const;

void reload();
private:
Expand Down
56 changes: 56 additions & 0 deletions src/core/Boxes/textbox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,10 @@ SkScalar TextBox::getFontSize() const {
return mFont.getSize();
}

SkScalar TextBox::getFontSpacing() const {
return mFont.getSpacing();
}

const QString& TextBox::getFontFamily() const {
return mFamily;
}
Expand All @@ -262,6 +266,58 @@ const QString& TextBox::getCurrentValue() const {
return mText->getCurrentValue();
}

QString TextBox::getValueAtRelFrame(const qreal relFrame) const {
return mText->getValueAtRelFrame(relFrame);
}

Qt::Alignment TextBox::getTextHAlignment() const {
return mHAlignment;
}

Qt::Alignment TextBox::getTextVAlignment() const {
return mVAlignment;
}

qreal TextBox::getLetterSpacing(const qreal relFrame) const {
return mLetterSpacing->getEffectiveValue(relFrame);
}

qreal TextBox::getWordSpacing(const qreal relFrame) const {
return mWordSpacing->getEffectiveValue(relFrame);
}

qreal TextBox::getLineSpacing(const qreal relFrame) const {
return mLineSpacing->getEffectiveValue(relFrame);
}

qreal TextBox::getMaxLineWidth(const qreal relFrame) const {
const QString textAtFrame = mText->getValueAtRelFrame(relFrame);
const qreal letterSpacing = mLetterSpacing->getEffectiveValue(relFrame);
const qreal wordSpacing = mWordSpacing->getEffectiveValue(relFrame);

qreal maxWidth = 0;
const QStringList lines = textAtFrame.split(QRegExp("\n|\r\n|\r"));
for(const auto& line : lines) {
maxWidth = qMax(maxWidth,
horizontalAdvance(mFont, line, letterSpacing, wordSpacing));
}
return maxWidth;
}

qreal TextBox::getTextWidth(const QString& text,
const qreal letterSpacing,
const qreal wordSpacing) const {
return horizontalAdvance(mFont, text, letterSpacing, wordSpacing);
}

SkPath TextBox::getTextPath(const QString& text,
const qreal x,
const qreal y) const {
SkPath path;
textToPath(x, y, text, path);
return path;
}

void TextBox::setupCanvasMenu(PropertyMenu * const menu)
{
if (menu->hasActionsForType<TextBox>()) { return; }
Expand Down
14 changes: 14 additions & 0 deletions src/core/Boxes/textbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,23 @@ class CORE_EXPORT TextBox : public PathBox {
Canvas * const scene);

SkScalar getFontSize() const;
SkScalar getFontSpacing() const;
const QString& getFontFamily() const;
const SkFontStyle& getFontStyle() const;
const QString& getCurrentValue() const;
QString getValueAtRelFrame(const qreal relFrame) const;
Qt::Alignment getTextHAlignment() const;
Qt::Alignment getTextVAlignment() const;
qreal getLetterSpacing(const qreal relFrame) const;
qreal getWordSpacing(const qreal relFrame) const;
qreal getLineSpacing(const qreal relFrame) const;
qreal getMaxLineWidth(const qreal relFrame) const;
qreal getTextWidth(const QString& text,
const qreal letterSpacing = 0,
const qreal wordSpacing = 1) const;
SkPath getTextPath(const QString& text,
const qreal x,
const qreal y) const;

void openTextEditor(QWidget* dialogParent);

Expand Down
11 changes: 11 additions & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,15 @@ set(
Animators/intanimator.cpp
Animators/key.cpp
Animators/boolanimator.cpp
lottie/dotlottiewriter.cpp
lottie/lottieexporter.cpp
lottie/lottieanimatedproperty.cpp
lottie/lottieblendmode.cpp
lottie/lottiejsonoptimizer.cpp
lottie/lottierealkeyframes.cpp
lottie/lottielayerbuilder.cpp
lottie/lottieparenting.cpp
lottie/lottiepatheffects.cpp
svgexporter.cpp
svgexporthelpers.cpp
svgimporter.cpp
Expand Down Expand Up @@ -717,6 +726,8 @@ set(
pointtypemenu.h
wrappedint.h
windowsincludes.h
lottie/dotlottiewriter.h
lottie/lottieparenting.h
zipfileloader.h
zipfilesaver.h
outputsettings.h
Expand Down
Loading
Loading