<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Video Editor – IMG.LY Blog</title><description>Posts tagged Video Editor on the IMG.LY blog.</description><link>https://img.ly/blog/tag/video-editor/</link><language>en-us</language><image><url>https://img.ly/apple-touch-icon.png</url><title>Video Editor – IMG.LY Blog</title><link>https://img.ly/blog/tag/video-editor/</link></image><atom:link href="https://img.ly/blog/tag/video-editor/rss.xml" rel="self" type="application/rss+xml"/><generator>Astro</generator><lastBuildDate>Wed, 02 Sep 2026 09:38:40 GMT</lastBuildDate><ttl>60</ttl><item><title>Building a CapCut-Like Video Editor with CE.SDK and AI</title><link>https://img.ly/blog/capcut-like-video-editor-web-react/</link><guid isPermaLink="true">https://img.ly/blog/capcut-like-video-editor-web-react/</guid><description>How to built a browser-based video editor with a dark CapCut-inspired UI, multi-track timeline, and AI-powered content generation... in under 200 lines of code.</description><pubDate>Thu, 26 Feb 2026 22:50:34 GMT</pubDate><content:encoded>&lt;h3 id=&quot;build-this-with-ai-in-minutes&quot;&gt;&lt;strong&gt;Build this with AI in minutes&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;This tutorial is a great way to understand how CE.SDK works under the hood. But if you just want to get to the result, you can build this entire editor using &lt;a href=&quot;https://img.ly/docs/cesdk/react/get-started/agent-skills-f7g8h9/&quot;&gt;IMG.LY Agent Skills&lt;/a&gt;, no manual setup required.&lt;/p&gt;
&lt;p&gt;Install the skills, then run:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;/cesdk:build Build a CapCut-like video editor with a dark theme, multi-track timeline, AI video/image/audio generation, background removal, and MP4 export.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Want to understand a specific concept in depth? Use &lt;code&gt;/cesdk:explain&lt;/code&gt;, for example:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;/cesdk:explain How does the video timeline and block hierarchy work?&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;CapCut has set the standard for accessible video editing. Its dark UI, intuitive timeline, and AI-powered features make it feel like a professional tool that anyone can use. But what if you could build something similar embedded directly in your own web application in minutes? Yes, minutes!&lt;/p&gt;
&lt;p&gt;In this tutorial, we’ll walk through how we built a CapCut-like video editor using &lt;a href=&quot;https://img.ly&quot;&gt;IMG.LY’s CreativeEditor SDK (CE.SDK)&lt;/a&gt; for React. The finished editor includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;multi-track timeline&lt;/strong&gt; for video, audio, text, and &lt;a href=&quot;https://img.ly/demos/video-captions/web/&quot;&gt;captions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trim, split, and join&lt;/strong&gt; operations on video clips&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;CapCut-inspired dark theme&lt;/strong&gt; built with CSS custom properties&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI video generation&lt;/strong&gt; (text-to-video, image-to-video) via Minimax, Kling, and Pixverse&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI image generation&lt;/strong&gt; (text-to-image, image editing) via RecraftV3, IdeogramV3, and GPT Image&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI audio generation&lt;/strong&gt; (text-to-speech, sound effects) via ElevenLabs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI text generation&lt;/strong&gt; (copywriting, translation) via Anthropic Claude&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Background removal&lt;/strong&gt; — client-side, powered by WebAssembly/WebGPU&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MP4 export&lt;/strong&gt; directly from the browser&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The entire editor is a single React component with roughly 180 lines of JavaScript and 100 lines of CSS.&lt;/p&gt;
&lt;h2 id=&quot;architecture-overview&quot;&gt;Architecture Overview&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;App architecture&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 2000px) 2000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;2000&quot; height=&quot;1969&quot; src=&quot;https://img.ly/_astro/Gemini_Generated_Image_6celpb6celpb6cel_4npMe.webp&quot; srcset=&quot;/_astro/Gemini_Generated_Image_6celpb6celpb6cel_Z2pUzxd.webp 640w, /_astro/Gemini_Generated_Image_6celpb6celpb6cel_1I72rW.webp 750w, /_astro/Gemini_Generated_Image_6celpb6celpb6cel_1YwWvd.webp 828w, /_astro/Gemini_Generated_Image_6celpb6celpb6cel_cWEce.webp 1080w, /_astro/Gemini_Generated_Image_6celpb6celpb6cel_22mCvu.webp 1280w, /_astro/Gemini_Generated_Image_6celpb6celpb6cel_Z1OLGCT.webp 1668w, /_astro/Gemini_Generated_Image_6celpb6celpb6cel_4npMe.webp 2000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;CE.SDK has two main layers:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;CreativeEngine:&lt;/strong&gt; The headless core that manages scenes, blocks, assets, and rendering. It handles the video timeline, playback, and export entirely client-side.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CreativeEditor UI:&lt;/strong&gt; A pre-built, customizable UI layer that wraps the engine with a dock, inspector, timeline, canvas, and navigation bar.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Plugins extend both layers. The &lt;code&gt;AiApps&lt;/code&gt; plugin, for example, registers AI providers with the engine and injects UI components (dock buttons, canvas menu items, generation panels) into the editor.&lt;/p&gt;
&lt;h2 id=&quot;step-1-project-setup&quot;&gt;Step 1: Project Setup&lt;/h2&gt;
&lt;p&gt;We scaffolded a React project with Vite and installed CE.SDK alongside the AI plugin packages:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; vite@latest&lt;/span&gt;&lt;span&gt; capcut-like-editor&lt;/span&gt;&lt;span&gt; --&lt;/span&gt;&lt;span&gt; --template&lt;/span&gt;&lt;span&gt; react&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; capcut-like-editor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# Core SDK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; @cesdk/cesdk-js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# AI plugins&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; @imgly/plugin-ai-apps-web&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; @imgly/plugin-ai-video-generation-web&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; @imgly/plugin-ai-image-generation-web&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; @imgly/plugin-ai-audio-generation-web&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; @imgly/plugin-ai-text-generation-web&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# Background removal (runs locally via WASM/WebGPU)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; @imgly/plugin-background-removal-web&lt;/span&gt;&lt;span&gt; onnxruntime-web@1.21.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;why-so-many-packages&quot;&gt;Why so many packages?&lt;/h3&gt;
&lt;p&gt;CE.SDK follows a modular plugin architecture. Each AI capability is a separate package with its own provider modules. This means you only bundle what you use if you don’t need audio generation, don’t install &lt;code&gt;@imgly/plugin-ai-audio-generation-web&lt;/code&gt;. The &lt;code&gt;@imgly/plugin-ai-apps-web&lt;/code&gt; package is the unifying layer that brings them all together into a single dock panel.&lt;/p&gt;
&lt;h2 id=&quot;step-2-the-react-component&quot;&gt;Step 2: The React Component&lt;/h2&gt;
&lt;p&gt;CE.SDK provides a first-class React wrapper via &lt;code&gt;@cesdk/cesdk-js/react&lt;/code&gt;. The &lt;code&gt;&amp;#x3C;CreativeEditor&gt;&lt;/code&gt; component handles mounting, initialization, and cleanup:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; CreativeEditor &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@cesdk/cesdk-js/react&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // license: &apos;YOUR_CESDK_LICENSE_KEY&apos;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; async&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;cesdk&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // All setup happens here — theme, assets, plugins, UI customization&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; VideoEditor&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;CreativeEditor&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{config} &lt;/span&gt;&lt;span&gt;init&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{init} &lt;/span&gt;&lt;span&gt;width&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;100vw&quot;&lt;/span&gt;&lt;span&gt; height&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;100vh&quot;&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;config&lt;/code&gt; object is passed to the engine at creation time. The &lt;code&gt;init&lt;/code&gt; callback fires once the &lt;code&gt;cesdk&lt;/code&gt; instance is ready. This is where all our customization lives.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall: Silent init errors.&lt;/strong&gt; The &lt;code&gt;&amp;#x3C;CreativeEditor&gt;&lt;/code&gt; component swallows errors thrown inside &lt;code&gt;init&lt;/code&gt;. If something fails, the editor loads but appears broken with no console output. Always wrap &lt;code&gt;init&lt;/code&gt; in a &lt;code&gt;try/catch&lt;/code&gt;:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;step-3-creating-the-video-scene&quot;&gt;Step 3: Creating the Video Scene&lt;/h2&gt;
&lt;p&gt;A video editor needs three things at startup: asset sources, a video scene, and a timeline.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// Load built-in asset libraries (stickers, shapes, filters, typefaces, etc.)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; cesdk.&lt;/span&gt;&lt;span&gt;addDefaultAssetSources&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// Load demo content (sample videos, images, audio) + enable upload slots&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; cesdk.&lt;/span&gt;&lt;span&gt;addDemoAssetSources&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  sceneMode: &lt;/span&gt;&lt;span&gt;&apos;Video&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  withUploadAssetSources: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// Create a video scene with timeline&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; cesdk.&lt;/span&gt;&lt;span&gt;createVideoScene&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;createVideoScene()&lt;/code&gt; sets up the scene hierarchy that powers the timeline:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Scene&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; └── Page (represents the video canvas — 1920x1080 by default)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      ├── Track (video track — holds video clips in sequence)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      ├── Track (overlay track — text, stickers, images)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      ├── CaptionTrack (subtitles synced to playback)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      └── Audio (background music, voiceover, sound effects)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each element on the timeline is a &lt;strong&gt;block&lt;/strong&gt; with timing properties: &lt;code&gt;timeOffset&lt;/code&gt; (when it appears) and &lt;code&gt;duration&lt;/code&gt; (how long it plays). The engine handles rendering each frame, compositing layers, and synchronizing audio.&lt;/p&gt;
&lt;h3 id=&quot;browser-support&quot;&gt;Browser support&lt;/h3&gt;
&lt;p&gt;Video editing relies on modern web codecs (WebCodecs API), which are available in Chromium-based browsers (Chrome, Edge, Brave). Safari and Firefox support is limited.&lt;/p&gt;
&lt;h2 id=&quot;step-4-the-capcut-dark-theme&quot;&gt;Step 4: The CapCut Dark Theme&lt;/h2&gt;
&lt;p&gt;CapCut’s visual identity is defined by its deep charcoal backgrounds, teal accent colors, and subtle elevation layers. CE.SDK’s theming system maps perfectly to this through CSS custom properties.&lt;/p&gt;
&lt;h3 id=&quot;setting-the-base-theme&quot;&gt;Setting the base theme&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cesdk.ui.&lt;/span&gt;&lt;span&gt;setTheme&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;dark&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This activates CE.SDK’s built-in dark theme. But we want to go further. We need CapCut’s specific color palette.&lt;/p&gt;
&lt;h3 id=&quot;custom-css-overrides&quot;&gt;Custom CSS overrides&lt;/h3&gt;
&lt;p&gt;CE.SDK scopes all its UI under &lt;code&gt;.ubq-public&lt;/code&gt; with &lt;code&gt;data-ubq-theme&lt;/code&gt; and &lt;code&gt;data-ubq-scale&lt;/code&gt; attributes. We override the CSS custom properties to inject our palette:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;.ubq-public&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;data-ubq-theme&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&apos;dark&apos;&lt;/span&gt;&lt;span&gt;][&lt;/span&gt;&lt;span&gt;data-ubq-scale&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&apos;normal&apos;&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;.ubq-public&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;data-ubq-theme&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&apos;dark&apos;&lt;/span&gt;&lt;span&gt;][&lt;/span&gt;&lt;span&gt;data-ubq-scale&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&apos;modern&apos;&lt;/span&gt;&lt;span&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  /* Deep charcoal backgrounds — darker than CE.SDK&apos;s default dark */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  --ubq-canvas&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;hsl&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;220&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;!important&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  --ubq-elevation-1&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;hsl&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;220&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;13&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;12&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;!important&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  --ubq-elevation-2&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;hsl&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;220&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;12&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;!important&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  --ubq-elevation-3&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;hsl&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;220&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;18&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;!important&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  /* High-contrast white text */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  --ubq-foreground-default&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;hsla&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0.92&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;!important&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  --ubq-foreground-light&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;hsla&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0.55&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;!important&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  /* CapCut&apos;s signature teal/cyan accent */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  --ubq-interactive-accent-default&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;hsl&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;190&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;85&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;48&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;!important&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  --ubq-interactive-accent-hover&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;hsl&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;190&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;85&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;42&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;!important&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  --ubq-interactive-accent-pressed&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;hsl&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;190&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;85&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;36&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;!important&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  /* Subtle borders — barely visible, like CapCut */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  --ubq-border-default&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;hsla&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0.08&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;!important&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The key design decisions:&lt;/p&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Property&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;th&gt;Why&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;--ubq-canvas&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;hsl(220, 15%, 8%)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Near-black with a slight blue tint — matches CapCut’s canvas area&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;--ubq-elevation-1/2/3&lt;/code&gt;&lt;/td&gt;&lt;td&gt;12% → 15% → 18% lightness&lt;/td&gt;&lt;td&gt;Subtle elevation steps create depth without harsh contrast&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;--ubq-interactive-accent-*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;hsl(190, 85%, 48%)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;CapCut’s teal — used for buttons, selections, and progress bars&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;--ubq-border-default&lt;/code&gt;&lt;/td&gt;&lt;td&gt;8% opacity white&lt;/td&gt;&lt;td&gt;Nearly invisible borders that only appear on close inspection&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;responsive-scale&quot;&gt;Responsive scale&lt;/h3&gt;
&lt;p&gt;We also configure responsive scaling so the editor adapts to touch devices:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cesdk.ui.&lt;/span&gt;&lt;span&gt;setScale&lt;/span&gt;&lt;span&gt;(({ &lt;/span&gt;&lt;span&gt;containerWidth&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;isTouch&lt;/span&gt;&lt;span&gt; }) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; ((containerWidth &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; containerWidth &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; 768&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; isTouch) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; &apos;large&apos;&lt;/span&gt;&lt;span&gt;; &lt;/span&gt;&lt;span&gt;// Bigger touch targets on small/touch screens&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; &apos;normal&apos;&lt;/span&gt;&lt;span&gt;; &lt;/span&gt;&lt;span&gt;// Standard desktop sizing&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;step-5-ai-plugin-integration&quot;&gt;Step 5: AI Plugin Integration&lt;/h2&gt;
&lt;p&gt;This is where the editor transforms from a basic video tool into something that feels like CapCut’s AI-powered experience. CE.SDK’s plugin system lets us add all AI capabilities through a single unified &lt;code&gt;AiApps&lt;/code&gt; plugin.&lt;/p&gt;
&lt;h3 id=&quot;the-unified-aiapps-approach&quot;&gt;The unified AiApps approach&lt;/h3&gt;
&lt;p&gt;Instead of registering each AI plugin separately, &lt;code&gt;@imgly/plugin-ai-apps-web&lt;/code&gt; provides a single entry point:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; AiApps &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@imgly/plugin-ai-apps-web&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; FalAiVideo &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@imgly/plugin-ai-video-generation-web/fal-ai&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; FalAiImage &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@imgly/plugin-ai-image-generation-web/fal-ai&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; OpenAiImage &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@imgly/plugin-ai-image-generation-web/open-ai&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; Elevenlabs &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@imgly/plugin-ai-audio-generation-web/elevenlabs&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; Anthropic &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@imgly/plugin-ai-text-generation-web/anthropic&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; cesdk.&lt;/span&gt;&lt;span&gt;addPlugin&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  AiApps&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    dryRun: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// Simulate for development — no API calls&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    providers: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      text2text: Anthropic.&lt;/span&gt;&lt;span&gt;AnthropicProvider&lt;/span&gt;&lt;span&gt;({ proxyUrl: &lt;/span&gt;&lt;span&gt;PROXY_URL&lt;/span&gt;&lt;span&gt; }),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      text2image: [FalAiImage.&lt;/span&gt;&lt;span&gt;RecraftV3&lt;/span&gt;&lt;span&gt;({ proxyUrl }) &lt;/span&gt;&lt;span&gt;/* ... */&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      image2image: [FalAiImage.&lt;/span&gt;&lt;span&gt;GeminiFlashEdit&lt;/span&gt;&lt;span&gt;({ proxyUrl }) &lt;/span&gt;&lt;span&gt;/* ... */&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      text2video: [FalAiVideo.&lt;/span&gt;&lt;span&gt;MinimaxVideo01Live&lt;/span&gt;&lt;span&gt;({ proxyUrl }) &lt;/span&gt;&lt;span&gt;/* ... */&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      image2video: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        FalAiVideo.&lt;/span&gt;&lt;span&gt;MinimaxVideo01LiveImageToVideo&lt;/span&gt;&lt;span&gt;({ proxyUrl }) &lt;/span&gt;&lt;span&gt;/* ... */&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      text2speech: Elevenlabs.&lt;/span&gt;&lt;span&gt;ElevenMultilingualV2&lt;/span&gt;&lt;span&gt;({ proxyUrl }),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      text2sound: Elevenlabs.&lt;/span&gt;&lt;span&gt;ElevenSoundEffects&lt;/span&gt;&lt;span&gt;({ proxyUrl }),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;provider-categories-explained&quot;&gt;Provider categories explained&lt;/h3&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Category&lt;/th&gt;&lt;th&gt;What it does&lt;/th&gt;&lt;th&gt;Models we configured&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;text2text&lt;/code&gt;&lt;/td&gt;&lt;td&gt;AI copywriting — improve text, translate, change tone&lt;/td&gt;&lt;td&gt;Anthropic Claude&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;text2image&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Generate images from text prompts&lt;/td&gt;&lt;td&gt;RecraftV3, IdeogramV3, GPT Image&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;image2image&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Transform existing images with AI&lt;/td&gt;&lt;td&gt;Gemini Flash Edit, GPT Image&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;text2video&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Generate video clips from text descriptions&lt;/td&gt;&lt;td&gt;Minimax Video, Kling Video, Pixverse&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;image2video&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Animate a static image into video&lt;/td&gt;&lt;td&gt;Minimax Video, Kling Video&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;text2speech&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Convert text to spoken audio with voice selection&lt;/td&gt;&lt;td&gt;ElevenLabs Multilingual V2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;text2sound&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Generate sound effects from text&lt;/td&gt;&lt;td&gt;ElevenLabs Sound Effects&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;When multiple providers are configured in an array (like &lt;code&gt;text2image&lt;/code&gt;), the UI automatically shows a provider/model selection dropdown so users can choose which AI model to use.&lt;/p&gt;
&lt;h3 id=&quot;the-proxy-server-requirement&quot;&gt;The proxy server requirement&lt;/h3&gt;
&lt;p&gt;Every provider takes a &lt;code&gt;proxyUrl&lt;/code&gt; parameter. This is critical for production:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Browser  →  Your Proxy Server  →  AI Provider (fal.ai, ElevenLabs, etc.)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                ↑&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          Injects API keys&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          server-side&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your API keys should never be in client-side code. The proxy server receives requests from CE.SDK, attaches your API key, and forwards to the AI provider. During development, &lt;code&gt;dryRun: true&lt;/code&gt; simulates generation without any API calls.&lt;/p&gt;
&lt;h3 id=&quot;background-removal&quot;&gt;Background removal&lt;/h3&gt;
&lt;p&gt;Background removal is a separate plugin because it runs entirely client-side, no proxy needed:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; BackgroundRemovalPlugin &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@imgly/plugin-background-removal-web&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; cesdk.&lt;/span&gt;&lt;span&gt;addPlugin&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  BackgroundRemovalPlugin&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ui: { locations: [&lt;/span&gt;&lt;span&gt;&apos;canvasMenu&apos;&lt;/span&gt;&lt;span&gt;] },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This uses ONNX Runtime (WebAssembly + WebGPU) to run an AI segmentation model directly in the browser. The first run downloads ~40MB of model weights, which are then cached. Select any image on the canvas and click “Remove Background” in the context menu.&lt;/p&gt;
&lt;h2 id=&quot;step-6-ui-customization-with-the-component-order-api&quot;&gt;Step 6: UI Customization with the Component Order API&lt;/h2&gt;
&lt;p&gt;CE.SDK’s UI is built from five customizable areas: &lt;strong&gt;Dock&lt;/strong&gt;, &lt;strong&gt;Inspector Bar&lt;/strong&gt;, &lt;strong&gt;Canvas Menu&lt;/strong&gt;, &lt;strong&gt;Navigation Bar&lt;/strong&gt;, and &lt;strong&gt;Canvas Bar&lt;/strong&gt;. The Component Order API lets us insert, remove, and reorder components in each area.&lt;/p&gt;
&lt;h3 id=&quot;adding-the-ai-button-to-the-dock&quot;&gt;Adding the AI button to the dock&lt;/h3&gt;
&lt;p&gt;We want the AI Apps button to be the first thing users see in the dock:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cesdk.ui.&lt;/span&gt;&lt;span&gt;insertOrderComponent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  { in: &lt;/span&gt;&lt;span&gt;&apos;ly.img.dock&apos;&lt;/span&gt;&lt;span&gt;, position: &lt;/span&gt;&lt;span&gt;&apos;start&apos;&lt;/span&gt;&lt;span&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;ly.img.ai.apps.dock&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;insertOrderComponent&lt;/code&gt; takes a location specifier and the component(s) to insert. &lt;code&gt;position: &apos;start&apos;&lt;/code&gt; puts it at the top of the dock. Alternative positions include &lt;code&gt;&apos;end&apos;&lt;/code&gt;, a numeric index, or relative placement with &lt;code&gt;before&lt;/code&gt;/&lt;code&gt;after&lt;/code&gt; matchers.&lt;/p&gt;
&lt;h3 id=&quot;ai-options-in-the-canvas-context-menu&quot;&gt;AI options in the canvas context menu&lt;/h3&gt;
&lt;p&gt;When a user selects a text or image block and right-clicks, we want AI options available:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cesdk.ui.&lt;/span&gt;&lt;span&gt;insertOrderComponent&lt;/span&gt;&lt;span&gt;({ in: &lt;/span&gt;&lt;span&gt;&apos;ly.img.canvas.menu&apos;&lt;/span&gt;&lt;span&gt;, position: &lt;/span&gt;&lt;span&gt;&apos;start&apos;&lt;/span&gt;&lt;span&gt; }, [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;ly.img.ai.text.canvasMenu&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;ly.img.ai.image.canvasMenu&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;]);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Passing an array inserts multiple components at once.&lt;/p&gt;
&lt;h3 id=&quot;custom-export-button-in-the-navigation-bar&quot;&gt;Custom export button in the navigation bar&lt;/h3&gt;
&lt;p&gt;We add an Export button with a real click handler that triggers MP4 export:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cesdk.ui.&lt;/span&gt;&lt;span&gt;insertOrderComponent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  { in: &lt;/span&gt;&lt;span&gt;&apos;ly.img.navigation.bar&apos;&lt;/span&gt;&lt;span&gt;, position: &lt;/span&gt;&lt;span&gt;&apos;end&apos;&lt;/span&gt;&lt;span&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    id: &lt;/span&gt;&lt;span&gt;&apos;ly.img.action.navigationBar&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    key: &lt;/span&gt;&lt;span&gt;&apos;export&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    label: &lt;/span&gt;&lt;span&gt;&apos;Export&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    icon: &lt;/span&gt;&lt;span&gt;&apos;@imgly/Download&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    onClick&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; engine&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; cesdk.engine;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; page&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;findByType&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;page&apos;&lt;/span&gt;&lt;span&gt;)[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      if&lt;/span&gt;&lt;span&gt; (page) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        const&lt;/span&gt;&lt;span&gt; blob&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;exportVideo&lt;/span&gt;&lt;span&gt;(page, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          mimeType: &lt;/span&gt;&lt;span&gt;&apos;video/mp4&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        const&lt;/span&gt;&lt;span&gt; url&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; URL&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;createObjectURL&lt;/span&gt;&lt;span&gt;(blob);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        const&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;a&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        a.href &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; url;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        a.download &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;video.mp4&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        a.&lt;/span&gt;&lt;span&gt;click&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        URL&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;revokeObjectURL&lt;/span&gt;&lt;span&gt;(url);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;exportVideo&lt;/code&gt; method renders every frame of the timeline (compositing video tracks, overlays, text, captions, and audio) into an MP4 blob entirely in the browser.&lt;/p&gt;
&lt;h2 id=&quot;step-7-wiring-generated-audio-into-the-asset-library&quot;&gt;Step 7: Wiring Generated Audio into the Asset Library&lt;/h2&gt;
&lt;p&gt;AI-generated audio (speech and sound effects) is stored in provider-specific history sources. To make this audio browsable alongside regular audio assets, we inject the history source into the audio asset library entry:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; audioEntry&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; cesdk.ui.&lt;/span&gt;&lt;span&gt;getAssetLibraryEntry&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;ly.img.audio&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (audioEntry &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; null&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; existingSourceIds&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; Array.&lt;/span&gt;&lt;span&gt;isArray&lt;/span&gt;&lt;span&gt;(audioEntry.sourceIds)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ?&lt;/span&gt;&lt;span&gt; audioEntry.sourceIds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    :&lt;/span&gt;&lt;span&gt; audioEntry.&lt;/span&gt;&lt;span&gt;sourceIds&lt;/span&gt;&lt;span&gt;({});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  cesdk.ui.&lt;/span&gt;&lt;span&gt;updateAssetLibraryEntry&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;ly.img.audio&apos;&lt;/span&gt;&lt;span&gt;, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    sourceIds: [&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;existingSourceIds, &lt;/span&gt;&lt;span&gt;&apos;ly.img.ai.audio-generation.history&apos;&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now when users open the Audio panel in the dock, they’ll see their AI-generated audio alongside the sample library.&lt;/p&gt;
&lt;h2 id=&quot;step-8-custom-labels-with-i18n&quot;&gt;Step 8: Custom Labels with i18n&lt;/h2&gt;
&lt;p&gt;CE.SDK’s i18n system lets us customize any UI string. We used it to make the AI prompt fields more inviting:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cesdk.i18n.&lt;/span&gt;&lt;span&gt;setTranslations&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  en: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &apos;ly.img.plugin-ai-video-generation-web.fal-ai/minimax/video-01-live.property.prompt&apos;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &apos;Describe your video...&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &apos;ly.img.plugin-ai-image-generation-web.fal-ai/recraft-v3.property.prompt&apos;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &apos;Describe your image...&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Translation keys follow the pattern &lt;code&gt;{plugin-id}.{provider-id}.property.{field}&lt;/code&gt;. You can also add multi-language support by including keys for &lt;code&gt;de&lt;/code&gt;, &lt;code&gt;fr&lt;/code&gt;, &lt;code&gt;es&lt;/code&gt;, etc.&lt;/p&gt;
&lt;h2 id=&quot;the-complete-file-structure&quot;&gt;The Complete File Structure&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;capcut-like-editor/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── src/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── App.jsx              # Root — imports VideoEditor + theme CSS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── VideoEditor.jsx      # The entire editor (single component, ~180 lines)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── capcut-theme.css     # CapCut dark theme overrides (~100 lines)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── index.css            # Global reset (margin/padding/overflow)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   └── main.jsx             # React entry point&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── index.html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── package.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;└── vite.config.js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s it. The entire CapCut-like editor is three files: one React component, one CSS file, and a thin App wrapper.&lt;/p&gt;
&lt;h2 id=&quot;what-we-get-out-of-the-box&quot;&gt;What We Get Out of the Box&lt;/h2&gt;
&lt;p&gt;Because CE.SDK’s video UI is pre-built, we didn’t write any code for these features. They come from &lt;code&gt;createVideoScene()&lt;/code&gt; and the default UI:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Multi-track timeline&lt;/strong&gt; with drag-to-reorder, drag-to-resize&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trim and split&lt;/strong&gt; — drag clip edges or use the split tool&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Join and arrange&lt;/strong&gt; — drag clips between tracks&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transform&lt;/strong&gt; — crop, flip, rotate via the inspector&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Playback controls&lt;/strong&gt; — play, pause, seek, scrub&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Text overlays&lt;/strong&gt; — add styled text with the text tool&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stickers and graphics&lt;/strong&gt; — from the asset library&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filters and effects&lt;/strong&gt; — LUT-based color grading&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Undo/redo&lt;/strong&gt; — full history stack&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zoom and pan&lt;/strong&gt; — standard canvas navigation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The AI plugins add their own UI components (dock buttons, generation panels, context menu items) through the plugin system. We just positioned them where we wanted.&lt;/p&gt;
&lt;h2 id=&quot;going-to-production&quot;&gt;Going to Production&lt;/h2&gt;
&lt;p&gt;To take this from a prototype to production, you need three things:&lt;/p&gt;
&lt;h3 id=&quot;1-license-key&quot;&gt;1. License key&lt;/h3&gt;
&lt;p&gt;Get a free trial key at &lt;a href=&quot;https://img.ly/forms/contact-sales/&quot;&gt;https://img.ly/forms/contact-sales/&lt;/a&gt; and set it in the config (yes, if you want to ship to production you’ll have to talk to our lovely colleagues in sales):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  license: &lt;/span&gt;&lt;span&gt;&apos;YOUR_CESDK_LICENSE_KEY&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-proxy-server&quot;&gt;2. Proxy server&lt;/h3&gt;
&lt;p&gt;Set up a server that forwards AI requests with your API keys:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; PROXY_URL&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &apos;https://your-server.com/api/ai-proxy&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See the &lt;a href=&quot;https://img.ly/docs/cesdk/react/user-interface/ai-integration/proxy-server-61f901/&quot;&gt;CE.SDK Proxy Server guide&lt;/a&gt; for Express.js and other server examples.&lt;/p&gt;
&lt;h3 id=&quot;3-disable-dry-run&quot;&gt;3. Disable dry run&lt;/h3&gt;
&lt;p&gt;Remove &lt;code&gt;dryRun: true&lt;/code&gt; from the AiApps configuration to enable real AI generation.&lt;/p&gt;
&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;CE.SDK does the heavy lifting.&lt;/strong&gt; The timeline, playback, rendering, and export are all handled by the engine. We wrote zero video processing code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The plugin system is powerful.&lt;/strong&gt; Six AI capabilities were added with a single &lt;code&gt;addPlugin(AiApps({ ... }))&lt;/code&gt; call. Background removal was one more call.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CSS custom properties make theming painless.&lt;/strong&gt; We matched CapCut’s aesthetic by overriding ~25 CSS variables. No forking, no patching.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Component Order API is the customization backbone.&lt;/strong&gt; &lt;code&gt;insertOrderComponent&lt;/code&gt; with position-based placement is the cleanest pattern for adding UI elements.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wrap &lt;code&gt;init&lt;/code&gt; in try/catch.&lt;/strong&gt; CE.SDK’s &lt;code&gt;&amp;#x3C;CreativeEditor&gt;&lt;/code&gt; swallows errors silently. This is the single most important debugging tip.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pin your package versions.&lt;/strong&gt; All &lt;code&gt;@imgly/*&lt;/code&gt; plugins must match the &lt;code&gt;@cesdk/cesdk-js&lt;/code&gt; version exactly. A version mismatch (like 1.68 vs 1.69) will cause peer dependency conflicts.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/react/starterkits/video-editor-e1nlor/&quot;&gt;CE.SDK Video Editor Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/react/user-interface/ai-integration/integrate-8e906c/&quot;&gt;AI Integration Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/react/user-interface/appearance/theming-4b0938/&quot;&gt;Theming Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/react/user-interface/customization/quick-start/reorder-components-f6g7h8/&quot;&gt;Rearrange Buttons (Component Order API)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/demos/video-ui/web/&quot;&gt;Video Editor Web Demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/imgly/cesdk-web-examples&quot;&gt;GitHub Examples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><dc:creator>Jan</dc:creator><media:content url="https://blog.img.ly/2026/02/blogcover.png" medium="image"/><category>React</category><category>Video Editor</category><category>CE.SDK</category></item><item><title>Best Video SDKs for Mobile Applications: A Comprehensive Comparison for Developers</title><link>https://img.ly/blog/best-video-sdks-for-mobile-applications-a-comprehensive-comparison-for-developers/</link><guid isPermaLink="true">https://img.ly/blog/best-video-sdks-for-mobile-applications-a-comprehensive-comparison-for-developers/</guid><description>Choosing the right video SDK for your mobile app is crucial. In this guide, we compare the top options in 2025: IMG.LY, Banuba, Meishe, BytePlus, FFmpeg, and GStreamer, to highlight their strengths, limitations, and ideal use cases so you can confidently pick the best fit for your product.</description><pubDate>Tue, 02 Dec 2025 14:54:37 GMT</pubDate><content:encoded>&lt;p&gt;If you’re building a mobile app that needs video editing capabilities, you’re facing a tough decision: should you integrate a commercial SDK, work with open-source tools, or try to build something yourself?&lt;/p&gt;
&lt;p&gt;Video editing on mobile isn’t just hard, it’s complex in ways that surprise even experienced developers. You’re dealing with device fragmentation, battery constraints, memory management, and user expectations shaped by apps like TikTok and CapCut. And unlike web apps, mobile video editing requires native performance optimization to feel responsive.&lt;/p&gt;
&lt;p&gt;In this article, we’ll compare the most popular &lt;strong&gt;video SDK options for mobile applications&lt;/strong&gt;: &lt;strong&gt;IMG.LY, Banuba, Meishe, BytePlus, FFmpeg, and GStreamer&lt;/strong&gt; and show you how they stack up across features, platforms, integration complexity, and pricing. We’ll be honest about where each solution shines and where you’ll hit roadblocks.&lt;/p&gt;
&lt;p&gt;We’ll also dig into what it actually takes to build with each option: difficulty of integration, performance considerations, and what happens when you need to scale beyond a prototype.&lt;/p&gt;
&lt;h2 id=&quot;the-challenge-building-video-editing-into-mobile-apps&quot;&gt;The Challenge: Building Video Editing Into Mobile Apps&lt;/h2&gt;
&lt;p&gt;Before diving into specific SDKs, let’s talk about why video editing on mobile is uniquely challenging.&lt;/p&gt;
&lt;h3 id=&quot;processing-power-vs-battery-life&quot;&gt;Processing Power vs Battery Life&lt;/h3&gt;
&lt;p&gt;Video processing is resource-intensive. Every frame you manipulate (trimming, filtering, compositing, exporting) requires significant CPU and GPU work. On mobile devices, this creates a constant tension between delivering fast performance and not draining your user’s battery in minutes.
Approximately 60% of battery usage in media apps comes from data transmission and processing. If you’re not careful with how you handle encoding, memory management, and background processes, your app will get uninstalled fast.&lt;/p&gt;
&lt;h3 id=&quot;device-fragmentation&quot;&gt;Device Fragmentation&lt;/h3&gt;
&lt;p&gt;Unlike web apps where you can control the environment, mobile apps run on thousands of device configurations. An iPhone 15 Pro handles 4K video editing effortlessly; a three-year-old Android phone might struggle with 1080p. You need to account for different chipsets, GPU capabilities, screen sizes, and OS versions, all while maintaining consistent UX.&lt;/p&gt;
&lt;h3 id=&quot;user-expectations-are-higher-than-ever&quot;&gt;User Expectations Are Higher Than Ever&lt;/h3&gt;
&lt;p&gt;Users expect mobile video editors to feel as responsive as native camera apps. They want real-time preview, smooth timeline scrubbing, instant filter application, and fast exports. Anything that feels sluggish or unpolished gets compared unfavorably to TikTok, Instagram, or CapCut (apps with massive engineering teams and years of optimization work).&lt;/p&gt;
&lt;p&gt;Building this level of polish from scratch is a multi-month (or multi-year) undertaking. That’s why most teams reach for an SDK.&lt;/p&gt;
&lt;h2 id=&quot;understanding-video-sdk-options&quot;&gt;Understanding Video SDK Options&lt;/h2&gt;
&lt;p&gt;The video SDK landscape breaks down into three broad categories:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Commercial SDKs&lt;/strong&gt; (IMG.LY Banuba, Meishe, BytePlus) provide pre-built editors with UI components, effects libraries, and dedicated support. They’re designed to integrate quickly but come with licensing costs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Open-source frameworks&lt;/strong&gt; (FFmpeg, GStreamer) give you powerful processing engines but no UI, no templates, and no hand-holding. You’ll need to build everything user-facing yourself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hybrid approaches&lt;/strong&gt; combine open-source processing with custom UI development, giving you flexibility at the cost of significant engineering time.&lt;/p&gt;
&lt;p&gt;When evaluating options, consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Do you need a user-facing editor or just backend processing?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How important is cross-platform consistency?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What’s your timeline and team size?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What happens when you need to scale or add new features?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now let’s break down each solution.&lt;/p&gt;
&lt;h2 id=&quot;1-imgly-cesdk-the-complete-solution&quot;&gt;1. IMG.LY CE.SDK (The Complete Solution)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;IMG.LY CreativeEditor SDK&lt;/strong&gt; is an enterprise-grade video editing solution built for teams that need production-ready editing features, cross-platform consistency, and automation, without spending months building and maintaining a custom solution.&lt;/p&gt;
&lt;p&gt;Unlike processing libraries (FFmpeg, GStreamer) or social-first SDKs (Banuba, BytePlus), IMG.LY provides both interactive editing and server-side automation in one platform. You can embed the SDK for user-facing editing and use the same engine for headless creative automation on your backend.&lt;/p&gt;
&lt;h3 id=&quot;core-capabilities&quot;&gt;Core Capabilities&lt;/h3&gt;
&lt;p&gt;IMG.LY delivers a complete video editing platform with timeline-based editing, design tools, and AI features:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Timeline-Based Editing:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Arrange videos on multi-track timelines&lt;/li&gt;
&lt;li&gt;Trim, crop, and adjust duration&lt;/li&gt;
&lt;li&gt;Merge videos and create collages&lt;/li&gt;
&lt;li&gt;Audio overlay and mixing&lt;/li&gt;
&lt;li&gt;Layer management and compositing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Creative Tools:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;60+ filters and effects&lt;/li&gt;
&lt;li&gt;Adjustments (brightness, contrast, saturation, exposure)&lt;/li&gt;
&lt;li&gt;Text design with custom fonts and styles&lt;/li&gt;
&lt;li&gt;Dynamic stickers and overlays&lt;/li&gt;
&lt;li&gt;Frames with multiple blend modes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Template System:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Design templates with text variables and placeholders&lt;/li&gt;
&lt;li&gt;Lockable elements for brand consistency&lt;/li&gt;
&lt;li&gt;Automated variation generation&lt;/li&gt;
&lt;li&gt;Server-side rendering for mass personalization&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;AI &amp;#x26; Automation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Native AI features: video generation, captions, voiceovers, thumbnails&lt;/li&gt;
&lt;li&gt;Model-agnostic plugin system (integrate any AI model or API)&lt;/li&gt;
&lt;li&gt;Background removal and style transfer&lt;/li&gt;
&lt;li&gt;Smart filters and enhancements&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Customization Framework:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Headless API for completely custom interfaces&lt;/li&gt;
&lt;li&gt;Theming to match your brand&lt;/li&gt;
&lt;li&gt;Toolbar configuration and element positioning&lt;/li&gt;
&lt;li&gt;Multi-language localization&lt;/li&gt;
&lt;li&gt;External asset library integration (Getty Images, Soundstripe)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;platform-support&quot;&gt;Platform Support&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Web:&lt;/strong&gt; JavaScript, React, Angular, Vue.js, Svelte, Next.js&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mobile:&lt;/strong&gt; Android (Kotlin/Java), iOS (Swift), React Native, Flutter&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Desktop:&lt;/strong&gt; macOS, Mac Catalyst, Electron&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Server:&lt;/strong&gt; Node.js for backend automation&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;technical-architecture&quot;&gt;Technical Architecture&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Client-side encoding&lt;/strong&gt; means fast editing operations run directly on devices without requiring backend infrastructure. This cuts bandwidth, reduces upload times for users, and eliminates server costs for standard editing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Server-side rendering&lt;/strong&gt; enables creative automation at scale, design templates once, generate thousands of variations programmatically from any data source with 100% consistent rendering.&lt;/p&gt;
&lt;h3 id=&quot;ideal-use-cases&quot;&gt;Ideal Use Cases&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Social media creation:&lt;/strong&gt; In-app video recording with dual-camera support, advanced audio overlays, and real-time effects&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Template-based workflows:&lt;/strong&gt; Automate video creation for marketing materials, product videos, social media ads&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enterprise automation:&lt;/strong&gt; Server-side rendering for high-volume ad generation, creative pipelines, mass personalization&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E-commerce:&lt;/strong&gt; Product video creation, user-generated content, personalized demos&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SaaS platforms:&lt;/strong&gt; In-app video editing for user-generated content, brand-controlled templates&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;real-customer-examples&quot;&gt;Real Customer Examples&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Social Media &amp;#x26; Content Creation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mobile apps use IMG.LY SDK for in-app video recording with dual-camera support, allowing creators to capture picture-in-picture content directly&lt;/li&gt;
&lt;li&gt;Advanced audio overlay features enable users to mix music tracks, voiceovers, and original audio in real-time&lt;/li&gt;
&lt;li&gt;Real-time effects and filters provide instant creative feedback during recording and editing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Template-Based Video Production:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Marketing teams design video templates once and generate thousands of personalized variations programmatically using server-side rendering&lt;/li&gt;
&lt;li&gt;E-commerce platforms automate product video creation by mapping product data to video templates, producing consistent branded content at scale&lt;/li&gt;
&lt;li&gt;Brand teams create locked templates with variable elements, ensuring on-brand output while allowing distributed teams to customize messaging&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Enterprise Creative Automation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ad platforms use CE.SDK’s Node.js capabilities for high-volume programmatic video generation, creating thousands of ad variations from single templates&lt;/li&gt;
&lt;li&gt;DAM systems integrate IMG.LY for in-workflow video editing, allowing teams to make quick adjustments without leaving their asset management platform&lt;/li&gt;
&lt;li&gt;Publishing platforms automate social media content by rendering video templates with dynamic data feeds, producing daily content without manual editing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;500+ million creations per month&lt;/strong&gt; powered by IMG.LY’s video editing and automation infrastructure across 600+ customers&lt;/p&gt;
&lt;h3 id=&quot;limitations&quot;&gt;Limitations&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Paid solution.&lt;/strong&gt; Unlike open-source frameworks, CE.SDK requires an enterprise license. This makes it less accessible for hobby projects or very early-stage prototypes, but the investment pays off in reduced development time, ongoing support, and scalability.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enterprise-focused.&lt;/strong&gt; The SDK is built for teams that need reliability, support, and scale. If you’re building a quick prototype or low-traffic app, open-source tools might be more cost-effective initially (though you’ll pay in engineering time).&lt;/p&gt;
&lt;h3 id=&quot;pricing--licensing&quot;&gt;Pricing / Licensing&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Custom enterprise licensing&lt;/strong&gt; based on platform, features, and usage&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dedicated support&lt;/strong&gt; included: onboarding, SLAs, regular updates&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integration time:&lt;/strong&gt; Most teams have a working editor in hours, not weeks&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;who-its-for&quot;&gt;Who It’s For&lt;/h3&gt;
&lt;p&gt;Businesses that need a &lt;strong&gt;complete, production-ready video editing solution&lt;/strong&gt; with cross-platform support, automation capabilities, enterprise scalability, and ongoing support. Teams that want to ship faster and focus on their unique product features rather than rebuilding video editing infrastructure.&lt;/p&gt;
&lt;h3 id=&quot;why-imgly-sdk-stands-out&quot;&gt;Why IMG.LY SDK Stands Out&lt;/h3&gt;
&lt;p&gt;While other SDKs focus on either interactive editing (Banuba, BytePlus) or backend processing (FFmpeg, GStreamer), &lt;strong&gt;IMG.LY is the only solution that combines:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cross-platform video editing (Web, iOS, Android, React Native, Flutter, Node.js)&lt;/li&gt;
&lt;li&gt;Polished editor UI with complete customization options&lt;/li&gt;
&lt;li&gt;Template system with server-side automation&lt;/li&gt;
&lt;li&gt;AI-powered creative features&lt;/li&gt;
&lt;li&gt;Dual-purpose architecture (client-side editing + server-side rendering)&lt;/li&gt;
&lt;li&gt;Enterprise-grade scalability and dedicated support&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you’re evaluating other SDKs, ask yourself: &lt;strong&gt;how much engineering time will you spend building, maintaining, and scaling a custom solution?&lt;/strong&gt; Our SDK eliminates that overhead so your team can focus on what makes your product unique.&lt;/p&gt;
&lt;h2 id=&quot;2-meishe-sdk&quot;&gt;2. Meishe SDK&lt;/h2&gt;
&lt;p&gt;Meishe is a Chinese video editing SDK provider with a comprehensive suite covering video editing, beauty filters, short video creation, and audio processing. They’re particularly strong in the Asian market and have been adopted by major platforms like Bilibili, OPPO, Xiaomi, and Himalaya.&lt;/p&gt;
&lt;h3 id=&quot;core-capabilities-1&quot;&gt;Core Capabilities&lt;/h3&gt;
&lt;p&gt;Meishe offers film and television-level processing capabilities with a focus on high-quality output:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video Editing Features:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Real-time preview through LiveWindow (preview effects during editing without pre-processing)&lt;/li&gt;
&lt;li&gt;Support for multiple file formats with input up to 4K&lt;/li&gt;
&lt;li&gt;Video output up to 1080P with configurable quality levels (1080P, 720P, 480P)&lt;/li&gt;
&lt;li&gt;Unlimited audio track editing with multi-segment support&lt;/li&gt;
&lt;li&gt;Transition effects between clips with customization options&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Creative Tools:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Real-time skin beautification with adjustable parameters&lt;/li&gt;
&lt;li&gt;Animation stickers with customizable properties&lt;/li&gt;
&lt;li&gt;Special effects filters&lt;/li&gt;
&lt;li&gt;Full-link HDR support&lt;/li&gt;
&lt;li&gt;Professional video/audio editing with free function combination&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical Details:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;4K shooting capability&lt;/li&gt;
&lt;li&gt;Real-time special effects processing&lt;/li&gt;
&lt;li&gt;Full-link HDR processing&lt;/li&gt;
&lt;li&gt;Professional-grade video and audio editing&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;platform-support-1&quot;&gt;Platform Support&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Native:&lt;/strong&gt; iOS, Android&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-Platform:&lt;/strong&gt; Flutter (with unified display across platforms)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ideal-use-cases-1&quot;&gt;Ideal Use Cases&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Enterprise applications requiring 4K video support&lt;/li&gt;
&lt;li&gt;Professional video editing apps&lt;/li&gt;
&lt;li&gt;Social media platforms (especially in Asian markets)&lt;/li&gt;
&lt;li&gt;Streaming and content creation apps&lt;/li&gt;
&lt;li&gt;Apps requiring HDR video processing&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;limitations-1&quot;&gt;Limitations&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Documentation primarily in Chinese.&lt;/strong&gt; While Meishe has English documentation, many resources and examples are primarily available in Chinese, which can create barriers for Western development teams.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Less Western market presence.&lt;/strong&gt; Most case studies and customer examples are from Chinese companies, which can make it harder to assess fit for Western markets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Customization complexity.&lt;/strong&gt; Getting deep customization may require more direct engagement with Meishe’s team compared to more self-service SDKs.&lt;/p&gt;
&lt;h3 id=&quot;pricing--licensing-1&quot;&gt;Pricing / Licensing&lt;/h3&gt;
&lt;p&gt;Pricing information is not publicly available. You’ll need to contact Meishe directly for quotes. This is common for enterprise-focused SDKs but can slow down evaluation.&lt;/p&gt;
&lt;h3 id=&quot;who-its-for-1&quot;&gt;Who It’s For&lt;/h3&gt;
&lt;p&gt;Development teams (especially in Asian markets) building professional-grade video editing apps that need 4K support, HDR processing, and advanced real-time capabilities.&lt;/p&gt;
&lt;h3 id=&quot;how-it-compares-to-imgly&quot;&gt;How it compares to IMG.LY&lt;/h3&gt;
&lt;p&gt;Meishe offers strong professional-grade video processing with 4K and HDR support, particularly well-suited for Asian markets. IMG.LY provides similar 4K capabilities but adds cross-platform consistency (including web and server), template-driven automation, and a more developer-friendly integration experience for global teams. Meishe’s documentation is primarily in Chinese, while IMG.LY offers comprehensive English documentation and Western market support. If you’re building for Asian markets with HDR requirements, Meishe is a strong choice. For global deployment with automation needs, IMG.LY’s unified platform across client and server offers broader flexibility.&lt;/p&gt;
&lt;h2 id=&quot;3-byteplus-video-editor-sdk&quot;&gt;3. BytePlus Video Editor SDK&lt;/h2&gt;
&lt;p&gt;BytePlus Video Editor SDK comes from ByteDance (the company behind TikTok and CapCut). It’s designed to replicate the short-form, social-first editing experience that made those platforms successful, giving app developers similar workflows and effects libraries.&lt;/p&gt;
&lt;h3 id=&quot;core-capabilities-2&quot;&gt;Core Capabilities&lt;/h3&gt;
&lt;p&gt;BytePlus provides three main feature sets built around social media video creation:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Camera Feature:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Real-time video capture and recording&lt;/li&gt;
&lt;li&gt;4K video recording on any mobile device&lt;/li&gt;
&lt;li&gt;Live filters and live beauty filters during capture&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Preview Editor Feature:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Video editing and composition tools&lt;/li&gt;
&lt;li&gt;More than 80,000 effects and filters&lt;/li&gt;
&lt;li&gt;AR stickers and visual enhancements&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Track Editor Feature:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Advanced multi-track timeline editing&lt;/li&gt;
&lt;li&gt;Speed change effects&lt;/li&gt;
&lt;li&gt;Transitions and audio features&lt;/li&gt;
&lt;li&gt;Multi-layer composition&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Export Options:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Support for 540p, 720p, 1080p, 4K resolutions&lt;/li&gt;
&lt;li&gt;Frame rates: 25fps, 30fps, 50fps, 60fps&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;platform-support-2&quot;&gt;Platform Support&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Native:&lt;/strong&gt; iOS (Cocoapods, SPM, Objective-C, SwiftUI), Android (Gradle, Java, Jetpack Compose)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-Platform:&lt;/strong&gt; React Native, Flutter&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Magic Template SDK:&lt;/strong&gt; Available for both platforms&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ideal-use-cases-2&quot;&gt;Ideal Use Cases&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Social media apps focused on user-generated content&lt;/li&gt;
&lt;li&gt;Short-form video platforms&lt;/li&gt;
&lt;li&gt;Apps that want TikTok-like editing workflows&lt;/li&gt;
&lt;li&gt;Content creation tools with extensive effects libraries&lt;/li&gt;
&lt;li&gt;Apps requiring machine learning-powered visual enhancements&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;limitations-2&quot;&gt;Limitations&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Effects and beauty features are separate.&lt;/strong&gt; The standard and lite versions of the SDK don’t include Camera props, filters, and beauty effects. You need to purchase those separately, which can complicate pricing and integration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Customization beyond theming is limited.&lt;/strong&gt; While you can match the SDK to your brand through theming, deeper UI customization requires more effort compared to headless SDKs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Annual licensing only.&lt;/strong&gt; The SDK operates on an annual subscription basis, which may not work for all business models or early-stage products.&lt;/p&gt;
&lt;h3 id=&quot;pricing--licensing-2&quot;&gt;Pricing / Licensing&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Annual subscription:&lt;/strong&gt; License valid for 1 year covering both iOS and Android&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contact sales&lt;/strong&gt; for pricing details&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integration time:&lt;/strong&gt; Estimated 2 weeks per platform (iOS &amp;#x26; Android) for one developer&lt;/li&gt;
&lt;li&gt;Customization may extend integration timeline&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;who-its-for-2&quot;&gt;Who It’s For&lt;/h3&gt;
&lt;p&gt;Teams building social media-style video apps that want to replicate TikTok’s editing experience, especially if you need access to a massive effects library and ByteDance’s proven video editing architecture.&lt;/p&gt;
&lt;h3 id=&quot;how-it-compares-to-imgly-1&quot;&gt;How it compares to IMG.LY&lt;/h3&gt;
&lt;p&gt;BytePlus brings TikTok’s proven social video editing architecture with 80,000+ effects and filters, making it ideal for replicating short-form social experiences. IMG.LY takes a different approach: instead of a massive pre-built effects library, it focuses on customization, templates, and automation. BytePlus excels at client-side social video creation with extensive effects; IMG.LY excels at template-driven workflows, server-side automation, and cross-platform consistency (including web and Node.js). If you want TikTok-like effects out of the box, BytePlus delivers. If you need creative automation, programmatic content generation, or want to build custom workflows with full control over the editing experience, IMG.LY offers more flexibility and a dual-purpose architecture.&lt;/p&gt;
&lt;h2 id=&quot;4-banuba-video-editor-sdk&quot;&gt;4. Banuba Video Editor SDK&lt;/h2&gt;
&lt;p&gt;Banuba is a commercial video editing SDK focused on social media apps, with a strong emphasis on AR effects and beauty filters. It’s designed for teams building TikTok-like experiences or apps where user-generated video content is central to the product.&lt;/p&gt;
&lt;h3 id=&quot;core-capabilities-3&quot;&gt;Core Capabilities&lt;/h3&gt;
&lt;p&gt;Banuba provides a full-featured video editor with AI-powered tools and creative effects:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video Editing Features:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Picture-in-picture for multi-video layouts&lt;/li&gt;
&lt;li&gt;AI-powered clipping that detects important segments&lt;/li&gt;
&lt;li&gt;Customizable templates with replaceable elements&lt;/li&gt;
&lt;li&gt;Trimming, merging, and timeline-based editing&lt;/li&gt;
&lt;li&gt;AI-generated captions (English, Mandarin, Spanish, Portuguese)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Creative Tools:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Face AR masks with morphing effects and animated backgrounds&lt;/li&gt;
&lt;li&gt;Video and transition effects (including “Rave” and “Cathode Flash”)&lt;/li&gt;
&lt;li&gt;Audio editing with recording and mixing&lt;/li&gt;
&lt;li&gt;Text and GIF overlays&lt;/li&gt;
&lt;li&gt;Beauty effects (skin smoothing, teeth whitening)&lt;/li&gt;
&lt;li&gt;Voice-change effects (Elf, Robot, Squirrel, Giant, Echo, Baritone)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical Details:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI algorithms work offline: all processing happens on the device&lt;/li&gt;
&lt;li&gt;No user content transmitted to servers&lt;/li&gt;
&lt;li&gt;Requires OpenGL ES 3.0 minimum (3.1 for GPU-accelerated neural networks)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;platform-support-3&quot;&gt;Platform Support&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Native:&lt;/strong&gt; iOS 15.0+, Android 6.0+&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-Platform:&lt;/strong&gt; React Native, Flutter, NativeScript&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ideal-use-cases-3&quot;&gt;Ideal Use Cases&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Social media applications with AR filters&lt;/li&gt;
&lt;li&gt;Photo/video editing apps for content creators&lt;/li&gt;
&lt;li&gt;E-commerce platforms with video demos&lt;/li&gt;
&lt;li&gt;Lifestyle and educational apps&lt;/li&gt;
&lt;li&gt;Short-form video content creation&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;limitations-3&quot;&gt;Limitations&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Pricing complexity.&lt;/strong&gt; Banuba’s pricing is custom and depends on platform, features, custom development, and payment terms. You’ll need to contact sales for accurate quotes, which can slow down evaluation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AR licensing.&lt;/strong&gt; Face AR features are optional and may require separate licensing, adding complexity to your commercial agreement.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Heavy focus on AR.&lt;/strong&gt; If you don’t need beauty filters or AR masks, you’re paying for features you won’t use.&lt;/p&gt;
&lt;h3 id=&quot;pricing--licensing-3&quot;&gt;Pricing / Licensing&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Free trial:&lt;/strong&gt; 14 days with all features&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Commercial:&lt;/strong&gt; Custom pricing based on platform, features, and usage&lt;/li&gt;
&lt;li&gt;Priced per platform per month&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;who-its-for-3&quot;&gt;Who It’s For&lt;/h3&gt;
&lt;p&gt;Teams building social media apps or content creation tools that need AR effects, beauty filters, and TikTok-like creative features out of the box.&lt;/p&gt;
&lt;h3 id=&quot;how-it-compares-to-imgly-2&quot;&gt;How it compares to IMG.LY&lt;/h3&gt;
&lt;p&gt;Banuba excels at AR effects and beauty filters for social media apps, while IMG.LY focuses on template-based workflows and cross-platform automation. If you need face masks and beauty effects, Banuba is purpose-built for that. But if you need server-side rendering, creative automation, or want the same editing engine across web, mobile, and backend, IMG.LY provides broader platform coverage and a dual-purpose architecture. Banuba is optimized for client-side social video creation; IMG.LY handles both interactive editing and programmatic content generation at scale.&lt;/p&gt;
&lt;h2 id=&quot;5-ffmpeg-via-ffmpegkit&quot;&gt;5. FFmpeg (via FFmpegKit)&lt;/h2&gt;
&lt;p&gt;FFmpeg is the industry-standard open-source tool for video processing. It’s not a video SDK in the traditional sense. It’s a command-line tool and set of libraries that handle encoding, decoding, transcoding, filtering, and nearly every video operation imaginable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FFmpegKit&lt;/strong&gt; is a wrapper that makes FFmpeg accessible on mobile platforms (Android, iOS, React Native, Flutter) through platform-specific APIs. It’s the primary way developers integrate FFmpeg into mobile apps.&lt;/p&gt;
&lt;h3 id=&quot;core-capabilities-4&quot;&gt;Core Capabilities&lt;/h3&gt;
&lt;p&gt;FFmpeg handles the entire video processing pipeline:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video Operations:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Encoding and decoding (every codec imaginable)&lt;/li&gt;
&lt;li&gt;Format conversion (MP4, MOV, AVI, MKV, WebM, etc.)&lt;/li&gt;
&lt;li&gt;Trimming, cutting, merging, splitting&lt;/li&gt;
&lt;li&gt;Filtering and effects&lt;/li&gt;
&lt;li&gt;Subtitle burning&lt;/li&gt;
&lt;li&gt;Video stabilization&lt;/li&gt;
&lt;li&gt;Audio extraction and mixing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical Features:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Command-line interface (via wrapper APIs)&lt;/li&gt;
&lt;li&gt;Support for hardware acceleration&lt;/li&gt;
&lt;li&gt;Concurrent command execution&lt;/li&gt;
&lt;li&gt;Extensive codec library&lt;/li&gt;
&lt;li&gt;Professional-grade output quality&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;platform-support-4&quot;&gt;Platform Support&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Native:&lt;/strong&gt; Android (Java API), iOS (Objective-C API), Linux (C++ API), macOS, tvOS&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-Platform:&lt;/strong&gt; Flutter (Dart API), React Native (JavaScript API with TypeScript definitions)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Eight prebuilt packages:&lt;/strong&gt; Distributed via Maven Central, CocoaPods, pub, npm&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ideal-use-cases-4&quot;&gt;Ideal Use Cases&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Backend video processing and transcoding&lt;/li&gt;
&lt;li&gt;Format conversion at scale&lt;/li&gt;
&lt;li&gt;Apps that need specific codec support&lt;/li&gt;
&lt;li&gt;Video compression and optimization&lt;/li&gt;
&lt;li&gt;Building custom video processing pipelines&lt;/li&gt;
&lt;li&gt;Server-side automation&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;limitations-4&quot;&gt;Limitations&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;No UI whatsoever.&lt;/strong&gt; FFmpeg is a processing engine. If you want users to interact with video (timelines, filters, previews), you’ll need to build the entire interface yourself from scratch.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Steep learning curve.&lt;/strong&gt; FFmpeg’s command-line syntax is powerful but complex. Even simple tasks require understanding flags, options, and codec parameters.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GPL licensing complexity.&lt;/strong&gt; While FFmpegKit itself is LGPL v3.0, including GPL-licensed libraries makes the entire bundle GPL v3.0, which has implications for commercial apps.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FFmpegKit has been officially retired.&lt;/strong&gt; As of June 2025, FFmpegKit is no longer maintained. Community-maintained forks exist, but official support is ending.&lt;/p&gt;
&lt;h3 id=&quot;pricing--licensing-4&quot;&gt;Pricing / Licensing&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Free and open-source:&lt;/strong&gt; LGPL v3.0 for FFmpegKit library&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPL v3.0&lt;/strong&gt; when GPL-licensed libraries are included&lt;/li&gt;
&lt;li&gt;Licensing depends on which codecs and libraries you bundle&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;who-its-for-4&quot;&gt;Who It’s For&lt;/h3&gt;
&lt;p&gt;Developers who need powerful backend video processing, format conversion, or transcoding, and are willing to build all user-facing features themselves. Not suitable for teams that need a ready-to-use editor.&lt;/p&gt;
&lt;h3 id=&quot;how-it-compares-to-imgly-3&quot;&gt;How it compares to IMG.LY&lt;/h3&gt;
&lt;p&gt;FFmpeg is a processing engine, not an editing SDK. It handles transcoding, format conversion, and video manipulation via command-line operations, but provides no UI, no templates, and no interactive editing components. IMG.LY includes a production-ready editor, template system, and user-facing tools out of the box, while also supporting server-side automation through Node.js. If you only need backend processing and are building all UI yourself, FFmpeg (via community forks) can work. If you need both interactive editing and automation, IMG.LY eliminates months of development by providing both in one platform. IMG.LY also avoids GPL licensing complications and the uncertainty of using a retired library with community forks.&lt;/p&gt;
&lt;h2 id=&quot;6-gstreamer-with-gstreamer-editing-services&quot;&gt;6. GStreamer (with GStreamer Editing Services)&lt;/h2&gt;
&lt;p&gt;GStreamer is a mature open-source multimedia framework used across Linux, Android, iOS, Windows, and macOS. It’s designed for building media applications (streaming, playback, recording, and non-linear editing) with a plugin-based architecture that makes it extremely flexible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GStreamer Editing Services (GES)&lt;/strong&gt; is a higher-level library built on top of GStreamer to simplify video editing application development. It was originally funded by Nokia for mobile video editing (“video editing in your pocket”).&lt;/p&gt;
&lt;h3 id=&quot;core-capabilities-5&quot;&gt;Core Capabilities&lt;/h3&gt;
&lt;p&gt;GStreamer provides the foundation for building multimedia applications:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Core Features:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Audio and video playback, recording, streaming&lt;/li&gt;
&lt;li&gt;Non-linear editing capabilities via GES&lt;/li&gt;
&lt;li&gt;Extensive plugin library (encoders, decoders, filters)&lt;/li&gt;
&lt;li&gt;Hardware acceleration support&lt;/li&gt;
&lt;li&gt;Low-latency streaming (RTSP, WebRTC)&lt;/li&gt;
&lt;li&gt;Support for diverse codecs and formats&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;GStreamer Editing Services:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;High-level API for creating editing applications&lt;/li&gt;
&lt;li&gt;Timeline-based editing&lt;/li&gt;
&lt;li&gt;Transition effects&lt;/li&gt;
&lt;li&gt;Audio mixing&lt;/li&gt;
&lt;li&gt;Asset management&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Performance Optimizations:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Offloading work to specialized hardware (DSPs, GPUs)&lt;/li&gt;
&lt;li&gt;Low power consumption for embedded processors&lt;/li&gt;
&lt;li&gt;Support for ARM, MIPS, SPARC architectures&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;platform-support-5&quot;&gt;Platform Support&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cross-Platform:&lt;/strong&gt; Linux, Android, iOS, Windows, macOS&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Language Bindings:&lt;/strong&gt; C++ (primary), Python, Java, JavaScript&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mobile:&lt;/strong&gt; Official SDK binaries for Android and iOS&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ideal-use-cases-5&quot;&gt;Ideal Use Cases&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Custom video editing apps requiring deep control&lt;/li&gt;
&lt;li&gt;Streaming applications (RTSP, WebRTC)&lt;/li&gt;
&lt;li&gt;Media players and recording apps&lt;/li&gt;
&lt;li&gt;Research and academic projects&lt;/li&gt;
&lt;li&gt;Embedded systems and IoT devices&lt;/li&gt;
&lt;li&gt;Apps requiring specialized codec support&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;limitations-5&quot;&gt;Limitations&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Steep learning curve.&lt;/strong&gt; GStreamer’s plugin-based architecture is powerful but complex. Understanding pipelines, bins, and element linking takes time even for experienced developers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No pre-built UI.&lt;/strong&gt; GES provides editing APIs, but you’ll need to build the entire interface yourself. This means designing everything: timelines, playback controls, effect panels, and export dialogs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Limited mobile-specific examples.&lt;/strong&gt; While GStreamer officially supports iOS and Android, production-ready mobile editing examples are scarce. You’ll be pioneering integration patterns yourself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Integration complexity.&lt;/strong&gt; Getting GStreamer running on mobile requires compiling binaries, managing dependencies, and debugging platform-specific issues. This isn’t a “drop in and go” integration.&lt;/p&gt;
&lt;h3 id=&quot;pricing--licensing-5&quot;&gt;Pricing / Licensing&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Free and open-source:&lt;/strong&gt; LGPL license&lt;/li&gt;
&lt;li&gt;GStreamer Editing Services included in main distribution&lt;/li&gt;
&lt;li&gt;No commercial support by default, but third-party companies (like Fluendo) offer commercial support and custom development&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;who-its-for-5&quot;&gt;Who It’s For&lt;/h3&gt;
&lt;p&gt;Teams with strong multimedia engineering expertise who need deep control over video processing and are willing to build everything from the ground up. Not suitable for teams that need fast time-to-market or lack video processing experience.&lt;/p&gt;
&lt;h3 id=&quot;how-it-compares-to-imgly-4&quot;&gt;How it compares to IMG.LY&lt;/h3&gt;
&lt;p&gt;GStreamer provides powerful low-level control over multimedia processing through its plugin-based architecture, making it ideal for specialized use cases like streaming, embedded systems, or custom pipelines. IMG.LY provides a higher-level, production-ready solution with UI components, templates, and automation built in. GStreamer requires significant expertise and months of development to build user-facing features; IMG.LY offers a working editor in hours with customization options that don’t require multimedia engineering expertise. If you need deep control over codecs, streaming protocols, or embedded deployment, GStreamer’s flexibility is unmatched. If you need to ship a production-ready video editor quickly with cross-platform support and automation capabilities, IMG.LY eliminates the complexity and provides enterprise support.&lt;/p&gt;
&lt;h2 id=&quot;comparison-table-video-sdks-for-mobile-applications&quot;&gt;Comparison Table: Video SDKs for Mobile Applications&lt;/h2&gt;












































































































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;strong&gt;Feature / SDK&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;Banuba&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;Meishe&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;BytePlus&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;FFmpeg&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;GStreamer&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;IMG.LY SDK&lt;/strong&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Platform Support&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;iOS 15+, Android 6+, React Native, Flutter, NativeScript&lt;/td&gt;&lt;td&gt;iOS, Android, Flutter&lt;/td&gt;&lt;td&gt;iOS, Android, React Native, Flutter&lt;/td&gt;&lt;td&gt;Android, iOS, React Native, Flutter, Linux, macOS&lt;/td&gt;&lt;td&gt;Linux, Android, iOS, Windows, macOS&lt;/td&gt;&lt;td&gt;Web, iOS, Android, React Native, Flutter, Desktop, Node.js&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;UI Included&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;✅ Pre-built editor&lt;/td&gt;&lt;td&gt;✅ Pre-built editor&lt;/td&gt;&lt;td&gt;✅ Pre-built editor&lt;/td&gt;&lt;td&gt;❌ Processing only&lt;/td&gt;&lt;td&gt;❌ GES provides APIs only&lt;/td&gt;&lt;td&gt;✅ Production-ready editor + Headless API&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Timeline Editing&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;✅ Yes&lt;/td&gt;&lt;td&gt;✅ Yes&lt;/td&gt;&lt;td&gt;✅ Multi-track&lt;/td&gt;&lt;td&gt;❌ Command-line only&lt;/td&gt;&lt;td&gt;✅ Via GES&lt;/td&gt;&lt;td&gt;✅ Advanced multi-track&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;AR / Beauty Filters&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;✅ Strong focus&lt;/td&gt;&lt;td&gt;✅ Real-time beauty&lt;/td&gt;&lt;td&gt;✅ 80,000+ effects&lt;/td&gt;&lt;td&gt;❌ None&lt;/td&gt;&lt;td&gt;❌ None&lt;/td&gt;&lt;td&gt;✅ Filters + extensible AI plugins&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Templates&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;✅ Customizable&lt;/td&gt;&lt;td&gt;⚠️ Limited info&lt;/td&gt;&lt;td&gt;✅ Magic Templates&lt;/td&gt;&lt;td&gt;❌ None&lt;/td&gt;&lt;td&gt;❌ None&lt;/td&gt;&lt;td&gt;✅ Advanced template system with variables&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Server-Side Automation&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;❌ No&lt;/td&gt;&lt;td&gt;❌ No&lt;/td&gt;&lt;td&gt;❌ No&lt;/td&gt;&lt;td&gt;✅ CLI-based&lt;/td&gt;&lt;td&gt;✅ Possible but complex&lt;/td&gt;&lt;td&gt;✅ Native support (same engine)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;AI Features&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;✅ AI clipping, captions&lt;/td&gt;&lt;td&gt;⚠️ Limited info&lt;/td&gt;&lt;td&gt;✅ ML-powered effects&lt;/td&gt;&lt;td&gt;❌ None&lt;/td&gt;&lt;td&gt;❌ None&lt;/td&gt;&lt;td&gt;✅ Native AI + model-agnostic plugins&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;4K Support&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;✅ Yes&lt;/td&gt;&lt;td&gt;✅ Up to 4K input&lt;/td&gt;&lt;td&gt;✅ 4K recording&lt;/td&gt;&lt;td&gt;✅ Yes&lt;/td&gt;&lt;td&gt;✅ Yes&lt;/td&gt;&lt;td&gt;✅ Yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Customization Level&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;⚠️ UI/UX + optional API&lt;/td&gt;&lt;td&gt;⚠️ Requires team engagement&lt;/td&gt;&lt;td&gt;⚠️ Theming primarily&lt;/td&gt;&lt;td&gt;✅ Complete control&lt;/td&gt;&lt;td&gt;✅ Complete control&lt;/td&gt;&lt;td&gt;✅ Headless API + theming + UI config&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Integration Complexity&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;⚠️ Moderate (GitHub samples)&lt;/td&gt;&lt;td&gt;⚠️ Moderate&lt;/td&gt;&lt;td&gt;⚠️ Moderate (~2 weeks)&lt;/td&gt;&lt;td&gt;⚠️ Complex (retired library)&lt;/td&gt;&lt;td&gt;⚠️ Very complex&lt;/td&gt;&lt;td&gt;✅ Simple (hours to integrate)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Documentation&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;✅ English, developer portal&lt;/td&gt;&lt;td&gt;⚠️ Primarily Chinese&lt;/td&gt;&lt;td&gt;✅ English, comprehensive&lt;/td&gt;&lt;td&gt;✅ Extensive community docs&lt;/td&gt;&lt;td&gt;✅ Extensive but complex&lt;/td&gt;&lt;td&gt;✅ Comprehensive with samples&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Licensing / Pricing&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Custom (free 14-day trial)&lt;/td&gt;&lt;td&gt;Contact for quote&lt;/td&gt;&lt;td&gt;Annual subscription&lt;/td&gt;&lt;td&gt;Free, LGPL/GPL&lt;/td&gt;&lt;td&gt;Free, LGPL&lt;/td&gt;&lt;td&gt;Enterprise license&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Enterprise Support&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;⚠️ Custom agreements&lt;/td&gt;&lt;td&gt;⚠️ Direct engagement&lt;/td&gt;&lt;td&gt;⚠️ ByteDance support&lt;/td&gt;&lt;td&gt;❌ Community only&lt;/td&gt;&lt;td&gt;⚠️ Third-party (Fluendo)&lt;/td&gt;&lt;td&gt;✅ Dedicated support + SLAs&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Best For&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Social media apps with AR focus&lt;/td&gt;&lt;td&gt;Professional apps in Asian markets&lt;/td&gt;&lt;td&gt;TikTok-like social video apps&lt;/td&gt;&lt;td&gt;Backend processing / transcoding&lt;/td&gt;&lt;td&gt;Custom multimedia apps&lt;/td&gt;&lt;td&gt;Cross-platform editing + automation at scale&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;making-your-decision-which-video-sdk-is-right-for-you&quot;&gt;Making Your Decision: Which Video SDK Is Right for You?&lt;/h2&gt;
&lt;p&gt;Here’s the honest breakdown based on your use case:&lt;/p&gt;
&lt;h3 id=&quot;choose-banuba-if&quot;&gt;Choose &lt;strong&gt;Banuba&lt;/strong&gt; if:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You’re building a social media app and AR effects are central to your product&lt;/li&gt;
&lt;li&gt;You need beauty filters, face masks, and creative effects out of the box&lt;/li&gt;
&lt;li&gt;Your primary audience expects TikTok-style creative tools&lt;/li&gt;
&lt;li&gt;You’re comfortable with custom pricing and optional feature licensing&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;choose-meishe-if&quot;&gt;Choose &lt;strong&gt;Meishe&lt;/strong&gt; if:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You’re targeting Asian markets where Meishe has strong adoption&lt;/li&gt;
&lt;li&gt;You need professional-grade 4K and HDR video processing&lt;/li&gt;
&lt;li&gt;Real-time preview and film-quality output are critical&lt;/li&gt;
&lt;li&gt;You have access to Chinese documentation resources or engineering support&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;choose-byteplus-if&quot;&gt;Choose &lt;strong&gt;BytePlus&lt;/strong&gt; if:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You want to replicate TikTok/CapCut’s editing experience&lt;/li&gt;
&lt;li&gt;You need access to 80,000+ effects and filters&lt;/li&gt;
&lt;li&gt;Machine learning-powered visual enhancements are important&lt;/li&gt;
&lt;li&gt;You’re comfortable with annual licensing and want ByteDance’s proven architecture&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;choose-ffmpeg-if&quot;&gt;Choose &lt;strong&gt;FFmpeg&lt;/strong&gt; if:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You need backend video processing, transcoding, or format conversion&lt;/li&gt;
&lt;li&gt;You’re building automation pipelines, not user-facing editors&lt;/li&gt;
&lt;li&gt;You have strong video engineering expertise&lt;/li&gt;
&lt;li&gt;You’re okay with command-line complexity and building all UI yourself&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Be aware:&lt;/strong&gt; FFmpegKit is officially retired; plan for community forks&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;choose-gstreamer-if&quot;&gt;Choose &lt;strong&gt;GStreamer&lt;/strong&gt; if:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You need deep control over multimedia processing&lt;/li&gt;
&lt;li&gt;You’re building custom streaming, playback, or editing applications&lt;/li&gt;
&lt;li&gt;You have strong multimedia engineering expertise&lt;/li&gt;
&lt;li&gt;You’re willing to invest significant time in integration and UI development&lt;/li&gt;
&lt;li&gt;You need specialized codec support or embedded system deployment&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;choose-imgly-cesdk-if&quot;&gt;Choose &lt;strong&gt;IMG.LY CE.SDK&lt;/strong&gt; if:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You need both interactive editing and server-side automation&lt;/li&gt;
&lt;li&gt;Cross-platform consistency is critical (Web, iOS, Android, React Native, Flutter)&lt;/li&gt;
&lt;li&gt;You want a production-ready editor that integrates in hours, not months&lt;/li&gt;
&lt;li&gt;Template-based workflows and creative automation are important&lt;/li&gt;
&lt;li&gt;You need enterprise support, SLAs, and ongoing updates&lt;/li&gt;
&lt;li&gt;Your team wants to focus on product features, not rebuilding video editing infrastructure&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;build-vs-buy-whats-the-real-cost&quot;&gt;Build vs Buy: What’s the Real Cost?&lt;/h2&gt;
&lt;p&gt;Let’s be honest about the engineering investment required:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Building on FFmpeg or GStreamer:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Months&lt;/strong&gt; to build a basic timeline editor with preview&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ongoing maintenance&lt;/strong&gt; for device compatibility, codec updates, performance optimization&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No UI components&lt;/strong&gt; — you’re building everything from scratch&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scaling challenges&lt;/strong&gt; when you need templates, automation, or new features&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Commercial SDKs (Banuba, Meishe, BytePlus):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Days to weeks&lt;/strong&gt; for basic integration&lt;/li&gt;
&lt;li&gt;Pre-built UI and effects libraries&lt;/li&gt;
&lt;li&gt;Dedicated support for troubleshooting&lt;/li&gt;
&lt;li&gt;Licensing costs vary; evaluate based on your revenue model&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;IMG.LY SDK:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hours&lt;/strong&gt; to integrate a working editor&lt;/li&gt;
&lt;li&gt;Production-ready UI with full customization&lt;/li&gt;
&lt;li&gt;Dual-purpose: client-side editing + server-side automation&lt;/li&gt;
&lt;li&gt;Template system and AI features included&lt;/li&gt;
&lt;li&gt;Enterprise support and regular updates&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ask yourself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What’s your timeline?&lt;/strong&gt; If you need to ship in weeks, open-source frameworks won’t get you there.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What’s your team’s expertise?&lt;/strong&gt; Video processing is complex; building from scratch requires specialized knowledge.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What happens when you scale?&lt;/strong&gt; Adding templates, automation, or AI features to a custom-built solution takes months of additional work.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Commercial SDKs cost money upfront but save significant engineering time. Open-source tools are “free” but expensive in development hours and opportunity cost.&lt;/p&gt;
&lt;h2 id=&quot;conclusion-the-right-sdk-depends-on-your-goals&quot;&gt;Conclusion: The Right SDK Depends on Your Goals&lt;/h2&gt;
&lt;p&gt;There’s no one-size-fits-all answer, but here’s the summary:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FFmpeg and GStreamer&lt;/strong&gt; are powerful processing engines for developers who need backend automation or custom pipelines. They give you complete control but require significant expertise and offer no user-facing components. Great for transcoding, format conversion, and specialized workflows, but not for building interactive editors.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Banuba, Meishe, and BytePlus&lt;/strong&gt; are excellent for social media apps that need AR effects, beauty filters, and TikTok-style editing. They provide pre-built editors with extensive effects libraries, but customization beyond theming can be limited, and they’re focused primarily on client-side editing (no server automation).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IMG.LY CE.SDK&lt;/strong&gt; is the only solution that combines production-ready interactive editing with server-side creative automation. We provide cross-platform consistency, a complete template system, AI features, and enterprise support, all in one platform. Where other SDKs require you to choose between editing and automation, we give you both.&lt;/p&gt;
&lt;p&gt;If you’re building an app where video editing is a core feature (not a side project), and you need to ship fast without compromising on quality or scalability, our SDK eliminates months of development work and ongoing maintenance headaches.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The real question isn’t “which SDK is cheapest?”&lt;/strong&gt; It’s &lt;strong&gt;“how much engineering time will we spend building, maintaining, and scaling a custom solution, and what could we build instead if we had that time back?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ready to see what IMG.LY SDK can do? &lt;a href=&quot;https://img.ly/demos/&quot;&gt;Explore our demos&lt;/a&gt; or &lt;a href=&quot;https://img.ly/forms/contact-sales/&quot;&gt;get in touch&lt;/a&gt; to discuss your project.&lt;/p&gt;</content:encoded><dc:creator>Klaudia</dc:creator><media:content url="https://blog.img.ly/2025/12/best-video-mobile-editor-sdk.jpg" medium="image"/><category>Video Editor</category><category>Mobile App Development</category><category>Insights</category></item><item><title>Best Open Source Video Editor SDKs: 2026 Roundup</title><link>https://img.ly/blog/best-open-source-video-editor-sdks-2025-roundup/</link><guid isPermaLink="true">https://img.ly/blog/best-open-source-video-editor-sdks-2025-roundup/</guid><description>Looking for the best open source video editor SDKs? Read this blog to get a comparison of the top solutions: FFmpeg, MoviePy, OpenShot Library, GStreamer, Remotion, and a commercial alternative: IMG.LY CE.SDK. </description><pubDate>Mon, 10 Nov 2025 11:13:59 GMT</pubDate><content:encoded>&lt;p&gt;If you’ve ever tried building a video editing feature from scratch, you know how quickly things can get complicated. Codecs, pipelines, formats, integrations, and performance tuning all come into play. &lt;/p&gt;
&lt;p&gt;That’s why developers often turn to open-source SDKs that make video processing more accessible and flexible.&lt;/p&gt;
&lt;p&gt;In this guide, we’ll break down some of the most widely used open-source video SDKs, focusing on how easy these tools are to build with, their use cases, and who they’re best for. We’ll also look at where open-source flexibility meets its limits, and how commercial SDKs like IMG.LY can save you time and complexity when building production-ready video products.&lt;/p&gt;
&lt;h2 id=&quot;1-ffmpeg&quot;&gt;&lt;strong&gt;1. FFmpeg&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Let’s start the comparison with one of the most popular open source video editor SDKs. FFmpeg is a command-line multimedia framework that powers much of the modern video ecosystem. It supports everything from transcoding to advanced automation, making it one of the most widely adopted open-source solutions for video processing.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; FFmpeg includes transcoding, filtering, cropping, resizing, overlaying, color grading, audio processing, and format conversion. Its flexibility comes from its powerful command-line interface, allowing developers to script nearly any video transformation task.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Platforms:&lt;/strong&gt; The tool offers broad cross-platform compatibility, running natively on Windows, macOS, and Linux. Its portability allows it to integrate into a wide range of development environments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Building difficulty &amp;#x26; potential roadblocks:&lt;/strong&gt; FFmpeg is quite difficult to learn and implement for beginners. It requires strong knowledge of scripting, codecs, and CLI-based workflows. Due to its steep learning curve, debugging complex filter chains can be time-consuming, and integrating it into GUI-based environments is also challenging. Developers must also navigate potential H.264 commercial licensing restrictions while using this tool.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Cases:&lt;/strong&gt; FFmpeg is best suited for server-side batch processing, video pipelines, and automated transcoding. While it excels in backend automation, it lacks an interactive editor UI or cross-platform embedding.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future-proofing, support &amp;#x26; pricing:&lt;/strong&gt; FFmpeg is a mature and stable project used across many industries for years, although its innovation is slow. Most developers using the tool rely on community forums and documentation for troubleshooting and setup help. It’s completely free and open-source, but encoding with certain codecs like H.264 may still require a separate commercial license.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Who it’s for:&lt;/strong&gt; This video editor SDK is ideal for developers handling large-scale backend video processing or transcoding tasks. It’s powerful and reliable, but not beginner-friendly or suited for products needing a visual editing interface.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;comparison-to-imgly&quot;&gt;&lt;strong&gt;Comparison to IMG.LY&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;FFmpeg is purely backend and lacks an interactive editor or cross-platform embedding capabilities. However, it performs exceptionally well in large-scale automation pipelines, where speed, reliability, and format support are critical. IMG.LY CE.SDK, by contrast, gives you a fully embeddable video editor, UI components, and automation workflows in a unified SDK. All without the complexity of manual scripting. &lt;/p&gt;
&lt;p&gt;Check out why &lt;a href=&quot;https://img.ly/ffmpeg-js-alternative/&quot;&gt;IMG.LY is a great alternative to FFmpeg&lt;/a&gt; here. &lt;/p&gt;
&lt;h2 id=&quot;2-moviepy&quot;&gt;&lt;strong&gt;2. MoviePy&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The next open source video editor on the list is MoviePy. It’s a Python library for programmatic video editing. It allows developers to edit video through code, making it particularly useful for automated workflows or content prototyping. &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; It supports cutting, compositing, adding text overlays, transitions, and visual effects. Developers can use Python scripts to build video sequences and automate rendering.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Platforms:&lt;/strong&gt; MoviePy works across all major platforms that support Python. It runs in standard Python environments without requiring extra setup, which makes it accessible for most developers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Building difficulty &amp;#x26; potential roadblocks:&lt;/strong&gt; MoviePy is easier to use than FFmpeg, but still requires scripting. It’s suitable for Python developers for prototyping, but it can struggle with performance when handling large video files. Developers often face challenges with dependency management and the absence of a real-time UI.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use cases:&lt;/strong&gt; This tool is best for automated content generation, research, and rapid prototyping of video workflows. It’s ideal for proof-of-concept projects where scripting flexibility matters more than performance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future-proofing, support &amp;#x26; pricing:&lt;/strong&gt; MoviePy is actively maintained by its niche community of developers. While it serves a smaller user base compared to larger frameworks, its reliability and accessibility make it a consistent choice for Python-based video projects. You can find support through community documentation that explains most functions clearly. It’s free and open-source, which makes it especially appealing for experimentation, research, and smaller-scale automation setups.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Who its for:&lt;/strong&gt; MoviePy is a great choice if you’re a Python developer wanting automation or experimental workflows. However, it’s not ideal for production-scale or interactive use cases due to performance limits and the absence of a UI. &lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;comparison-to-imgly-1&quot;&gt;&lt;strong&gt;Comparison to IMG.LY&lt;/strong&gt; &lt;/h3&gt;
&lt;p&gt;MoviePy is designed for scripting and backend automation. It works best for creating short automated clips or experimental workflows where developers want full control through Python code. &lt;/p&gt;
&lt;p&gt;IMG.LY CE.SDK goes beyond backend scripting by offering ready-to-embed editors, automation APIs, and full multi-platform support for web and mobile. This makes it a more complete choice if your team needs both automation and interactive editing within products.  &lt;/p&gt;
&lt;h2 id=&quot;3-openshot-library--mlt-framework&quot;&gt;&lt;strong&gt;3. OpenShot Library / MLT Framework&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The OpenShot Library, built on the MLT Framework, is a C++/Python library for video compositing and timeline editing. It powers the OpenShot video editor and can be integrated into custom desktop applications.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; It provides timeline editing, transitions, effects, and audio mixing. Developers can implement advanced video composition features similar to traditional desktop editors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Platforms:&lt;/strong&gt; The library is cross-platform, working reliably across major desktop operating systems, including Windows, macOS, and Linux. It can be integrated into various environments, which makes it useful if you’re building desktop editors or applications that require timeline-based video editing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Building difficulty &amp;#x26; potential roadblocks:&lt;/strong&gt; The integration complexity is medium-high, as the API can be unstable, and managing dependencies can be difficult. Developers may also encounter documentation gaps, making it challenging to set up and maintain. Integrating the library into a GUI is not straightforward, and limited server-side automation means it is less suited for scalable or cloud-based workflows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use cases:&lt;/strong&gt; OpenShot Library is suitable for you if you’re looking to build desktop-based editors, experimental timeline tools, or custom video composition applications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future-proofing, support &amp;#x26; pricing:&lt;/strong&gt; The framework is actively maintained and works well for desktop video editing applications. However, it is not designed for server-side automation or large-scale deployment. The support is community-driven, so the updates and fixes depend on volunteer contributions, which can affect long-term reliability for enterprise use. The framework is free and open-source, making it accessible to anyone looking to experiment or build lightweight video editing tools.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Who its for:&lt;/strong&gt; OpenShot/MLT fits developers building desktop-focused editors who need timeline control but can manage API and dependency challenges. It’s less practical for cloud or mobile workflows.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;comparison-to-imgly-2&quot;&gt;&lt;strong&gt;Comparison to IMG.LY&lt;/strong&gt; &lt;/h3&gt;
&lt;p&gt;While OpenShot/MLT excels in desktop-based timeline editing, it is better suited for applications that prioritize local processing and desktop workflows. &lt;/p&gt;
&lt;p&gt;IMG.LY CE.SDK, on the other hand, offers embedded, cross-platform editors with built-in automation, making it a more versatile choice for SaaS and enterprise environments that need scalability, faster integration, and an intuitive editing experience for end users.&lt;/p&gt;
&lt;h2 id=&quot;4-gstreamer&quot;&gt;&lt;strong&gt;4. GStreamer&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;GStreamer is a multimedia framework for building video and audio pipelines. It’s a foundational tool in many streaming and broadcast systems and allows developers to create complex pipelines for capturing, processing, and outputting media in real time.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; This open source video editor supports real-time processing, filters, and complex pipelines for media processing and streaming. Developers can construct customized processing chains for advanced workflows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Platforms:&lt;/strong&gt; GStreamer is cross-platform, supporting multiple programming languages with bindings for C, Python, Java, and Rust. You can run it on Windows, macOS, and Linux, and integrate it into both desktop and server environments. This makes it flexible for building diverse media workflows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Building difficulty &amp;#x26; potential roadblocks:&lt;/strong&gt; Building with GStreamer is complex. It requires deep knowledge of pipelines and plugins, and debugging can be time-intensive. UI integration adds another layer of difficulty.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use cases:&lt;/strong&gt; Despite its building difficulty, developers use GStreamer for real-time video streaming, server-side processing, and for broadcast applications requiring precise control over data flow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future-proofing, support &amp;#x26; pricing:&lt;/strong&gt; GStreamer is mature and widely used in the media industry. It continues to be a reliable choice for building streaming and broadcast systems, but it requires significant development expertise to configure and maintain. Developers often rely on community resources for support, though some commercial assistance is available. It’s free and open-source, which makes it accessible for experimentation and custom media workflows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Who it’s for:&lt;/strong&gt; The tool is ideal for developers who need real-time video pipelines or streaming capabilities. But it may not be a fit for applications requiring easy embedding or interactive UIs. &lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;comparison-to-imgly-3&quot;&gt;&lt;strong&gt;Comparison to IMG.LY&lt;/strong&gt; &lt;/h3&gt;
&lt;p&gt;GStreamer operates at the infrastructure level, ideal for backend media processing where you need precise control over data flow and performance. It gives you the flexibility to build custom video pipelines, but doing so requires significant technical effort and time. &lt;/p&gt;
&lt;p&gt;IMG.LY provides a ready-to-embed, interactive editor with automation and multi-platform support, so you can focus on building user experiences rather than managing low-level media infrastructure.&lt;/p&gt;
&lt;h2 id=&quot;5-remotion&quot;&gt;&lt;strong&gt;5. Remotion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Remotion enables developers to create videos programmatically using React components. Developers can define video scenes, transitions, and animations directly in React. While it’s a flexible approach, building long or high-resolution videos can demand careful optimization to ensure smooth performance.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; It supports timeline-based video composition, text overlays, animations, audio integration, and programmatic transitions, all rendered through React. Developers can create videos entirely with code, defining scenes and effects inside React components.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Platforms:&lt;/strong&gt; Remotion is built for Node.js and browser-based environments via headless rendering. You can render videos directly in the browser or on a Node.js server, which gives developers flexibility in how they deploy and automate video creation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Building difficulty &amp;#x26; potential roadblocks:&lt;/strong&gt; Building difficulty using Remotion is at a medium level because it requires React and JavaScript proficiency. The potential issues you might face while using this include debugging challenges with high-resolution or long-duration renders, along with limited server-side optimization that can affect scalability and performance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use cases:&lt;/strong&gt; Remotion is well-suited for automated video generation, marketing content, and dynamic SaaS video templates. You can use it to create personalized videos or promotional content at scale, using data or user inputs to generate customized output.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future-proofing, support &amp;#x26; pricing:&lt;/strong&gt; The tool is actively maintained and is built with a modern web stack using React and TypeScript, which ensures long-term stability and adaptability. You can find help through detailed documentation, GitHub issues, and an engaged developer community. While it doesn’t offer formal support, its open-source nature encourages collaboration and contributions that keep the framework improving. Like other tools we’ve discussed, this is also free and open-source, making it an accessible choice for developers exploring programmatic video creation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Who it’s for:&lt;/strong&gt; Based on its features and capabilities, it’s best for React developers who want to generate videos programmatically. However, it lacks an interactive editor and may not scale easily for enterprise automation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;comparison-to-imgly-4&quot;&gt;&lt;strong&gt;Comparison to IMG.LY&lt;/strong&gt; &lt;/h3&gt;
&lt;p&gt;Remotion excels in programmatic video creation, allowing you to build videos entirely through code with precision and flexibility. However, it lacks interactive editing tools or native SDKs that can be directly embedded into products. &lt;/p&gt;
&lt;p&gt;IMG.LY CE.SDK, by comparison, gives you both automation capabilities and user-facing editors across platforms, helping teams build complete video experiences without maintaining separate systems. You can find more information on &lt;a href=&quot;https://img.ly/remotion-alternative/&quot;&gt;how IMG.LY compares to Remotion here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;6-imgly-cesdk&quot;&gt;&lt;strong&gt;6. IMG.LY CE.SDK&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;A commercial solution that offers enterprise-grade functionality and developer-friendly implementation.&lt;/p&gt;
&lt;p&gt;IMG.LY CreativeEditor SDK is built for interactive video editing and automation. It gives developers the tools to build powerful, embeddable video editors without the complexity of starting from scratch. It balances the flexibility developers expect from open-source frameworks with the stability and support of a commercial-grade platform.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; It includes timeline editing, multi-layer video composition, templates, AI-assisted editing, transitions, video export, and server-side automation. The SDK simplifies complex workflows by offering prebuilt editors and APIs for integration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Platforms:&lt;/strong&gt; Available on Web, iOS, Android, React Native, Flutter, Node.js, and Electron. This broad platform support allows developers to build consistent video editing experiences across desktop, mobile, and web environments. Whether you’re integrating into an existing app or launching a new product, the IMG.LY CE SDK ensures a unified editing interface and workflow across all platforms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Building difficulty &amp;#x26; potential roadblocks:&lt;/strong&gt; Integration is straightforward, with minimal setup required, making it the easiest SDK to build with among all the tools we compared in this list. Most implementation effort lies in customizing workflows rather than solving technical barriers. This simplicity comes from well-documented APIs, prebuilt UI components, and consistent cross-platform behavior, which together reduce the development time. Potential roadblocks are minimal, allowing you to focus on building product features instead of managing infrastructure or compatibility issues.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use cases:&lt;/strong&gt; IMG.LY is best suited for SaaS apps, marketing automation, social content tools, and video personalization platforms that need seamless interactive editing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future-proofing, support &amp;#x26; pricing:&lt;/strong&gt; &lt;a href=&quot;https://img.ly/whats-new/&quot;&gt;Frequent releases&lt;/a&gt;, an expanding AI roadmap, and a scalable engine ensure long-term reliability for developers and enterprises. You get access to dedicated onboarding engineers, solution architects, and enterprise SLAs that make implementation and scaling easier. Pricing follows a custom enterprise licensing model, offering flexibility for different business needs. But you can &lt;a href=&quot;https://img.ly/docs/cesdk/&quot;&gt;take a free trial to get started.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Who it’s for: I&lt;/strong&gt;MG.LY is designed for companies that need scalable, interactive video editing and automation in one package. Its ideal for teams seeking low development overhead and enterprise-grade reliability.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;why-imgly-stands-out-as-the-best-open-source-video-editor-sdk&quot;&gt;&lt;strong&gt;Why IMG.LY stands out as the best open source video editor SDK&lt;/strong&gt; &lt;/h3&gt;
&lt;p&gt;IMG.LY combines interactive editing, server-side automation, and multi-platform SDKs in one stack, giving you everything needed to build scalable, modern video products. You can create, edit, and automate workflows within the same ecosystem without relying on separate tools. None of the open-source options on this list deliver this level of integration and consistency across web, mobile, and desktop environments.&lt;/p&gt;
&lt;p&gt;Check out how IMG.LY has helped over 600 innovative startups, government entities, and Fortune 500 companies to streamline their design, video, and photo editing workflows. &lt;a href=&quot;https://img.ly/case-studies/&quot;&gt;Read our case studies here.&lt;/a&gt; &lt;/p&gt;
&lt;h2 id=&quot;overview-table&quot;&gt;&lt;strong&gt;Overview table&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Here’s a brief overview of all the video editor SDKs we’ve discussed to help you choose the right one. &lt;/p&gt;

















































































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Feature / Use Case&lt;/th&gt;&lt;th&gt;&lt;strong&gt;FFmpeg&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;MoviePy&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;OpenShot / MLT&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;GStreamer&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;Remotion&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;IMG.LY CE.SDK&lt;/strong&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Timeline editing&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;❌ No GUI timeline; timeline-like operations only possible via scripting in CLI.&lt;/td&gt;&lt;td&gt;⚠️ Timeline functionality simulated through Python scripts; suitable for small-scale projects.&lt;/td&gt;&lt;td&gt;✅ Native timeline-based video editing with GUI; library supports composition though GUI integration can be limited.&lt;/td&gt;&lt;td&gt;⚠️ Pipeline-centric; timeline must be assembled programmatically, no native GUI timeline.&lt;/td&gt;&lt;td&gt;✅ Timeline created programmatically using React components; no interactive GUI timeline.&lt;/td&gt;&lt;td&gt;✅ Full-featured interactive timeline, multi-layer support, drag-and-drop UI&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Filters &amp;#x26; Effects&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;✅ Supports CLI-based filters, overlays, color correction; requires manual configuration&lt;/td&gt;&lt;td&gt;✅ Python effects library; scripting needed to combine filters&lt;/td&gt;&lt;td&gt;✅ Built-in video effects and transitions; limited prebuilt UI&lt;/td&gt;&lt;td&gt;✅ Plugin-based filters; flexible but requires pipeline setup&lt;/td&gt;&lt;td&gt;✅ Animations, text overlays, audio effects via scripting; programmatic transitions&lt;/td&gt;&lt;td&gt;✅ AI-enhanced effects, transitions, multi-layer composition, background removal&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Server-side automation&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;✅ Excellent for backend batch processing and transcoding; CLI automation is robust&lt;/td&gt;&lt;td&gt;✅ Python scripting enables automated content generation&lt;/td&gt;&lt;td&gt;⚠️ Limited server-side automation; mainly library-level&lt;/td&gt;&lt;td&gt;✅ Suitable for large-scale pipelines and streaming&lt;/td&gt;&lt;td&gt;✅ Automated video rendering via Node.js; works with server-side scripts&lt;/td&gt;&lt;td&gt;✅ Full automation APIs; combines server-side rendering + interactive editing in one SDK&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Ease of embedding&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;❌ CLI only; difficult to embed in apps&lt;/td&gt;&lt;td&gt;⚠️ Python scripts can be integrated, but no GUI&lt;/td&gt;&lt;td&gt;⚠️ Library-only; integration requires custom UI&lt;/td&gt;&lt;td&gt;⚠️ Complex pipelines; requires deep development knowledge&lt;/td&gt;&lt;td&gt;⚠️ Node.js / headless browser integration possible; UI must be custom-built&lt;/td&gt;&lt;td&gt;✅ Ready-to-embed SDKs for Web, iOS, Android, React Native, Flutter; includes prebuilt editors&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Difficulty building / integration&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;High — complex CLI usage, codec handling, and scripting required&lt;/td&gt;&lt;td&gt;Medium — Python knowledge required, scripting-intensive&lt;/td&gt;&lt;td&gt;Medium-High — API can be unstable, dependencies must be managed&lt;/td&gt;&lt;td&gt;High — pipeline setup and plugin management are challenging&lt;/td&gt;&lt;td&gt;Medium — React knowledge needed; performance optimization may be required&lt;/td&gt;&lt;td&gt;Low — SDK provides prebuilt editor components and APIs for easy integration&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Potential roadblocks&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;CLI complexity, codec licensing (H.264), debugging pipelines, no GUI&lt;/td&gt;&lt;td&gt;Large videos may be slow, performance issues, dependency management&lt;/td&gt;&lt;td&gt;API instability, documentation gaps, integration with UI requires effort&lt;/td&gt;&lt;td&gt;Steep learning curve, pipeline debugging, plugin version conflicts&lt;/td&gt;&lt;td&gt;Rendering performance for long/high-resolution videos, debugging programmatic scripts&lt;/td&gt;&lt;td&gt;Minimal; most challenges relate to workflow decisions during integration&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Cross-platform support&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;✅ Desktop/server; Windows, macOS, Linux&lt;/td&gt;&lt;td&gt;✅ Desktop/server; cross-platform Python&lt;/td&gt;&lt;td&gt;✅ Desktop/server; cross-platform&lt;/td&gt;&lt;td&gt;✅ Desktop/server; cross-platform&lt;/td&gt;&lt;td&gt;✅ Node.js + headless browser; works across server environments&lt;/td&gt;&lt;td&gt;✅ Web + mobile + desktop; consistent UI across platforms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;AI / Automation&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;❌ None&lt;/td&gt;&lt;td&gt;❌ None&lt;/td&gt;&lt;td&gt;❌ None&lt;/td&gt;&lt;td&gt;❌ None&lt;/td&gt;&lt;td&gt;⚠️ Programmatic automation via scripting&lt;/td&gt;&lt;td&gt;✅ AI-assisted editing, automation workflows, plugin ecosystem&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Scalability&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;✅ Excellent for batch and server pipelines&lt;/td&gt;&lt;td&gt;⚠️ Limited; performance depends on scripting and hardware&lt;/td&gt;&lt;td&gt;⚠️ Medium; suitable for desktop-scale apps&lt;/td&gt;&lt;td&gt;✅ Large-scale pipelines, real-time streaming&lt;/td&gt;&lt;td&gt;✅ Programmatic generation can scale, but may need server resources&lt;/td&gt;&lt;td&gt;✅ Enterprise-grade; cloud-ready, multi-platform, high-volume video workflows&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Pricing&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Free, OSS; H.264 encoding may require commercial license&lt;/td&gt;&lt;td&gt;Free, OSS&lt;/td&gt;&lt;td&gt;Free, OSS&lt;/td&gt;&lt;td&gt;Free, OSS&lt;/td&gt;&lt;td&gt;Free, OSS&lt;/td&gt;&lt;td&gt;Custom enterprise licensing&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Best For&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Developers building automation pipelines, server-side video processing, or streaming workflows&lt;/td&gt;&lt;td&gt;Python developers building scripted video content and automation&lt;/td&gt;&lt;td&gt;Developers building desktop-focused video apps with timeline editing&lt;/td&gt;&lt;td&gt;Developers needing real-time pipelines or advanced streaming&lt;/td&gt;&lt;td&gt;Developers using React for programmatic video generation and templating&lt;/td&gt;&lt;td&gt;Companies needing interactive, embedded video editing + AI automation + multi-platform SDK&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;choosing-the-right-video-sdk-how-to-make-the-right-choice&quot;&gt;&lt;strong&gt;Choosing the right video SDK: How to make the right choice&lt;/strong&gt; &lt;/h2&gt;
&lt;p&gt;When choosing the right video SDK, the best option depends on what you’re building and who it’s for.&lt;/p&gt;
&lt;p&gt;Choose open-source SDKs like FFmpeg, MoviePy, OpenShot/MLT, GStreamer, and Remotion if you prefer flexibility and complete control. These tools are free, customizable, and well-suited for automation, research, or proof-of-concept projects. However, they often require significant development time, scripting knowledge, and ongoing maintenance, which can slow down production or scaling.&lt;/p&gt;
&lt;p&gt;For teams building commercial or enterprise-ready video products, commercial SDKs offer a more practical route. They save you time on integration, provide dedicated support, and come with consistent updates to ensure reliability across platforms.&lt;/p&gt;
&lt;p&gt;That’s why developers choose IMG.LY SDK.&lt;/p&gt;
&lt;p&gt;It combines interactive editing, automation, and cross-platform SDKs in a single stack, something open-source solutions can’t fully replicate. It’s designed for SaaS, social, and enterprise use cases where scalability, ease of use, and performance matter most. You can embed editors, automate workflows, and scale confidently without managing multiple systems.&lt;/p&gt;
&lt;p&gt;So if you want a complete, production-ready platform with AI features, automation, and an intuitive editing experience, IMG.LY is the right choice. &lt;/p&gt;
&lt;p&gt;Get in touch with our team to see how it’s deployed in over 500 applications and used by millions of users across 29 countries. &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/&quot;&gt;Start a free trial&lt;/a&gt; or &lt;a href=&quot;https://img.ly/forms/contact-sales/&quot;&gt;book your call today&lt;/a&gt;!&lt;/p&gt;</content:encoded><dc:creator>Vatsala</dc:creator><media:content url="https://blog.img.ly/2025/11/open-source-video-editor-sdk-whitelabel-best-comparison--1-.jpg" medium="image"/><category>Video Editing</category><category>Video Editor</category><category>OpenSource</category><category>Insights</category></item><item><title>The Top 7 Video Editing SDKs in 2026</title><link>https://img.ly/blog/top-7-video-editing-sdks-in-2025/</link><guid isPermaLink="true">https://img.ly/blog/top-7-video-editing-sdks-in-2025/</guid><description>In this guide, we break down the seven leading video editing SDK solutions: IMG.LY, Meishe, Banuba, Shotstack, BytePlus, Rendley, and Picsart, covering their features, platforms, use cases, and trade-offs. </description><pubDate>Tue, 02 Sep 2025 11:19:08 GMT</pubDate><content:encoded>&lt;p&gt;With dozens of video editing SDKs on the market, choosing the right one can feel like a daunting task.&lt;/p&gt;
&lt;p&gt;To help you cut through the noise, we’ve put together a breakdown of the &lt;strong&gt;7 best video editing SDKs in 2026:&lt;/strong&gt; IMG.LY, Meishe SDK, Banuba, Shotstack, BytePlus Effects, Rendley, and Picsart. We’ll cover:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Key features and capabilities&lt;/li&gt;
&lt;li&gt;Supported platforms and customization options&lt;/li&gt;
&lt;li&gt;Ideal use cases and trade-offs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This guide is unbiased, but we’ll also highlight how IMG.LY compares and where it stands out as the only solution that combines a polished editor with scalable automation in a single package.&lt;/p&gt;
&lt;h2 id=&quot;1-imgly-creativeeditor-sdk-cesdk&quot;&gt;&lt;strong&gt;1. IMG.LY CreativeEditor SDK (CE.SDK)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Choosing IMG.LY means selecting a platform that offers both: a Canva-grade editor for your users and a powerful Engine API for automation. That dual focus is what sets CE.SDK apart.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; CE.SDK works best when you see it as a bridge between what end users expect and what your product team needs behind the scenes. On the surface, users get familiar tools including multi‑track editing, ready‑made templates, and a growing set of AI features like text‑to‑image, text‑to‑video, and AI voiceovers. Behind the scenes, developers can extend and customise with a plugin system so the editor adapts as your product evolves.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Platforms &amp;#x26; customization:&lt;/strong&gt; This flexibility carries over to platforms. CE.SDK works across Web, iOS, Android, React Native, Flutter, Electron, and Node.js. It’s also fully white‑label, which means your customers see a seamless extension of your brand, not a third‑party tool.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Implementation &amp;#x26; use cases:&lt;/strong&gt; Getting started with our tool doesn’t require a huge lift. Teams can spin up a proof of concept quickly, then scale into enterprise deployment when ready. That’s why you’ll see CE.SDK inside SaaS platforms, e‑commerce personalization tools, DAM systems, and even social networks.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Future‑proofing, support &amp;#x26; pricing&lt;/strong&gt;: What reassures teams is the long‑term roadmap: regular feature releases, AI integrations, and direct support from solution engineers. Enterprise SLAs and SSO come standard. Pricing depends on the usage, which makes it easier to scale without committing to rigid licensing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Who it’s for:&lt;/strong&gt; CE.SDK is valuable for SaaS, MarTech, e-commerce, and DAM platforms. These teams need to give users a simple, branded editing experience while also managing complex automation in the background. Instead of stitching together multiple tools or sacrificing one capability for another, CE.SDK provides an all-in-one foundation: polished editing, scalable automation, enterprise-grade support, and ongoing AI-driven innovation.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;key-differentiator&quot;&gt;&lt;strong&gt;Key differentiator&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;CE.SDK doesn’t force you to choose between usability and power. On one side, it delivers a polished, user-facing editor that feels familiar to end users. On the other hand, it provides a powerful automation engine that scales with your product. Most SDKs lean heavily in one direction. They either focus on end-user editing or specialize in backend automation. CE.SDK is different because it combines both in a single platform.&lt;/p&gt;
&lt;h2 id=&quot;2-meishe-sdk-meicam&quot;&gt;&lt;strong&gt;2. Meishe SDK (Meicam)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Meishe SDK, also known as Meicam, is a mature Chinese SDK that has carved out a space in many professional apps across Asia. Think of it as a toolkit built for industries that need stability and advanced editing power, though it comes with a few trade‑offs that teams should weigh carefully.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; Meishe offers multi‑track timelines, real‑time effects, and plugin support across mobile, web, and PC. Industries like automotive, broadcasting, and education have already used Meishe successfully, showing how it handles complex and demanding video workflows.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Platforms &amp;#x26; customization:&lt;/strong&gt; It supports full UI customization, white‑labeling, and plugins. And while customization depth is solid, integration tends to be heavier compared to other tools. Documentation can feel dense, which sometimes slows teams down as they work toward launch.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Implementation &amp;#x26; use cases:&lt;/strong&gt; Meishe SDK is beginning to layer in AI integrations like intelligent editing and motion tracking. For large organizations in Asia with strong internal dev resources, these capabilities can be appealing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Future‑proofing, support &amp;#x26; pricing:&lt;/strong&gt; Meishe continues to expand with new AI features like facial recognition and virtual anchors. It also offers custom enterprise support agreements. However, teams often struggle with the integration process, and the developer experience feels less polished. Setting up complex projects can take longer, and the documentation isn’t as approachable, which leaves some developers hesitant to adopt it widely. Pricing typically follows an enterprise licensing model, which can be less flexible for fast‑scaling SaaS companies.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Who it’s for:&lt;/strong&gt; Meishe SDK is best suited for large-scale apps in Asia and companies with internal dev resources.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-it-compares-to-imgly&quot;&gt;&lt;strong&gt;How it compares to IMG.LY&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Meishe delivers solid editing capabilities and is a proven choice in professional and regional contexts. But the trade‑offs become clear when you look at integration and support. It can feel heavy to implement, and documentation isn’t as approachable.&lt;/p&gt;
&lt;p&gt;IMG.LY pulls ahead here with stronger web support, compatibility with creative file types like PSD, AI, and INDD, and a faster onboarding process that makes it easier for teams to move from idea to production.&lt;/p&gt;
&lt;p&gt;Learn more about how &lt;a href=&quot;https://img.ly/meishesdk-alternative/&quot;&gt;IMG.LY compares to Meishe SDK here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;3-banuba&quot;&gt;&lt;strong&gt;3. Banuba&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Banuba is a mobile‑first SDK with a strong focus on augmented reality (AR). It has built its reputation on powering social and UGC apps with effects that mimic the TikTok experience. If your product relies on immersive filters, beauty effects, or virtual try‑on, Banuba often appears at the top of the evaluation list.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; The SDK provides a TikTok‑like editor with AR masks, beauty filters, face tracking, background removal, and even virtual try‑on features. These tools are designed to keep users engaged with interactive and shareable content.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Platforms &amp;#x26; customization:&lt;/strong&gt; Banuba supports iOS, Android, Flutter, and React Native. It offers modular components with a preset UI, which makes implementation faster for mobile. That said, customization options are limited when compared to solutions designed for enterprise-level flexibility.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Implementation &amp;#x26; use cases:&lt;/strong&gt; Integration is relatively quick for mobile teams, and the SDK has proven popular among social media platforms, beauty apps, and e‑commerce companies offering AR try‑on. However, support for web or large‑scale enterprise environments is limited, which narrows its scope.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Future‑proofing, support &amp;#x26; pricing:&lt;/strong&gt; The company continues to expand its AR and AI features, focusing on personalization and beauty‑driven effects. Banuba operates with a smaller team of about 70 employees, which can affect the pace of enterprise‑grade support. Licensing costs are typically high and not publicly disclosed, which may be a barrier for smaller companies.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Who it’s for:&lt;/strong&gt; Banuba is best suited for mobile apps that need advanced AR features like beauty filters, face tracking, or virtual try‑on to keep users engaged.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-it-compares-to-imgly-1&quot;&gt;&lt;strong&gt;How it compares to IMG.LY&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Banuba leads when it comes to AR‑driven capabilities, making it a natural fit for beauty and social platforms. But when teams look beyond filters to enterprise readiness, automation, and cross‑platform support, other options such as IMG.LY offer broader possibilities.&lt;/p&gt;
&lt;p&gt;Learn more about how &lt;a href=&quot;https://img.ly/banuba-alternative/&quot;&gt;IMG.LY compares to Banuba here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;4-shotstack&quot;&gt;&lt;strong&gt;4. Shotstack&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Shotstack focuses squarely on automation. It’s a cloud‑based video editing API designed for bulk rendering rather than end‑user editing. Teams often evaluate it when they need to generate thousands of videos quickly and at scale.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; Shotstack runs on a JSON‑driven API that lets developers programmatically create and assemble video content. With this approach, teams can handle automated ad generation, personalization, or large‑scale marketing campaigns. While powerful for automation, it doesn’t include a native editor, which means you must build a custom UI if you want end‑user editing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Platforms &amp;#x26; customization:&lt;/strong&gt; Shotstack is built as a REST API in the cloud, so it fits naturally into modern development stacks. It allows teams to design workflows programmatically, though the absence of prebuilt UI components makes it harder to use the tool right away as compared to other SDKs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Implementation &amp;#x26; use cases:&lt;/strong&gt; Developers appreciate the smooth onboarding experience and clear API structure. Typical use cases include bulk rendering of ads, dynamic personalization for campaigns, and other scenarios where scaling output matters more than in‑app editing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Future‑proofing, support &amp;#x26; pricing:&lt;/strong&gt; Shotstack continues to invest in automation and AI‑powered generation, offering tools that personalize video creation at scale. The vendor provides commercial SLAs, but support resources remain limited given the team size. Pricing follows a pay‑as‑you‑go model ($0.30 per minute) or subscription plans, which can work well for predictable, high‑volume usage.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Who it’s for:&lt;/strong&gt; Shotstack is best suited for teams that need scalable rendering pipelines and automation rather than in‑app editing features.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-it-compares-to-imgly-2&quot;&gt;&lt;strong&gt;How it compares to IMG.LY&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Shotstack gives you powerful rendering automation and programmatic workflows. IMG.LY takes it further by combining those automation strengths with a complete, user‑facing editor, so you can address both your development needs and your end‑users’ experiences in one solution.&lt;/p&gt;
&lt;p&gt;Get a detailed &lt;a href=&quot;https://img.ly/shotstack-alternative/&quot;&gt;comparison of IMG.LY CreativeEditor SDK and Shotstack&lt;/a&gt; here.&lt;/p&gt;
&lt;h2 id=&quot;5-byteplus-effects&quot;&gt;&lt;strong&gt;5. BytePlus Effects&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;BytePlus Effects is modelled after TikTok and CapCut. It’s designed to give app developers the same kind of short‑form, social‑first experience that has made those platforms successful. As a result, it appeals to teams that want to replicate TikTok‑like engagement inside their own apps.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; The SDK offers more than 80,000 effects and filters, including AR stickers and beautification tools. These features aim to keep users engaged by giving them endless ways to personalize and enhance their content.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Platforms &amp;#x26; customization:&lt;/strong&gt; BytePlus integrates with iOS, Android, React Native, and Flutter, making it a strong option for mobile‑first development. You can customise the UI to match your brand, but customization beyond theming is limited, which can be a constraint if you need deeper control.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Implementation &amp;#x26; use cases:&lt;/strong&gt; Since it’s optimized for mobile integration, you can embed it relatively quickly into short‑form consumer video apps. Common use cases include social platforms, beauty apps, and any consumer‑facing product that thrives on AR‑enhanced video.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Future‑proofing, support &amp;#x26; pricing:&lt;/strong&gt; With the backing of TikTok’s ecosystem, BytePlus is evolving rapidly, adding new AI‑driven AR and beauty effects frequently. However, commercial support feels less transparent, and licensing comes through enterprise negotiations with annual fees. This structure can work for large consumer platforms, but may be harder for smaller teams.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Who it’s for:&lt;/strong&gt; BytePlus is best suited for apps that want to recreate TikTok‑style user experiences and rely heavily on prebuilt AR effects to keep users engaged.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-it-compares-to-imgly-3&quot;&gt;&lt;strong&gt;How it compares to IMG.LY&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;BytePlus takes a step ahead when it comes to prebuilt effects and AR‑driven experiences. But if you need more flexibility in customization, automation capabilities, or enterprise‑grade workflows, IMG.LY offers a broader solution.&lt;/p&gt;
&lt;p&gt;For a detailed comparison, take a look at our guide on &lt;a href=&quot;https://img.ly/byteplus-alternative/&quot;&gt;IMG.LY vs BytePlus Video Editor.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;6-rendley&quot;&gt;&lt;strong&gt;6. Rendley&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Rendley is a newer player in the SDK space and has gained attention because of its browser‑only approach. It’s JavaScript‑based and runs entirely in the browser, which means you don’t need a server to get started. This makes it attractive for teams that want a lightweight, client‑only setup without managing infrastructure.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; The SDK supports multi‑track editing, keyframes, and even integrates with After Effects (AE). These features give frontend developers enough flexibility to build interactive editing experiences directly in the browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Platforms &amp;#x26; customization:&lt;/strong&gt; Rendley runs entirely in the browser, which makes it a natural fit for lightweight web apps and UGC platforms. Developers get flexibility through an open, in‑browser approach. However, without enterprise‑level frameworks, scaling to larger organizations becomes more difficult.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Implementation &amp;#x26; use cases:&lt;/strong&gt; Setting up Rendley is straightforward for frontend teams, which makes it appealing for lightweight UGC applications or smaller web projects. That ease of entry, however, comes with limits: AI integrations aren’t a core focus, so its potential for more advanced future applications remains restricted.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Future‑proofing, support &amp;#x26; pricing:&lt;/strong&gt; Rendley is still early‑stage and hasn’t yet proven itself at enterprise scale. Support is provided by a small vendor team, which can make long‑term stability less certain. Pricing details are not publicly available, leaving prospective users to negotiate directly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Who it’s for:&lt;/strong&gt; Rendley fits developers who want a browser‑native, client‑only editing tool without the need for server infrastructure.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-it-compares-to-imgly-4&quot;&gt;&lt;strong&gt;How it compares to IMG.LY&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Rendley works well as a lightweight, browser‑native solution. But if you need enterprise‑grade robustness, automation, or dedicated support, IMG.LY offers more comprehensive coverage.&lt;/p&gt;
&lt;p&gt;Learn more about how &lt;a href=&quot;https://img.ly/rendley-alternative/&quot;&gt;IMG.LY is a great alternative for Rendley&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;7-picsart-video-sdk&quot;&gt;&lt;strong&gt;7. Picsart Video SDK&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Picsart Video SDK is an embeddable video editor SDK that brings Picsart’s creative editing tools into third-party apps or websites.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; This SDK brings the company’s well‑known creative editing tools into third‑party products. Out of the box, you get features like trimming, multi‑scene editing, transitions, dynamic audio, subtitles, and text overlays, enough to cover the basics of video creation. AI‑driven tools extend these capabilities with smarter image and video editing options.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Platforms &amp;#x26; customization:&lt;/strong&gt; The SDK is React Native‑based but optimized for web embedding, making it appealing for web‑first platforms. You can configure the UI, apply theming, white‑label the experience, toggle features on or off, and integrate your own asset library so the editor matches your product’s design and workflow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Implementation &amp;#x26; use cases:&lt;/strong&gt; One of Picsart’s strengths is ease of setup: installation is fast, with a React editor installation process that reduces complexity, documentation is detailed, and the editor is designed to embed with minimal lift. This makes it a good choice for advertising or marketing platforms, edu‑tech products, and media platforms that want to give users creative tools quickly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Future‑proofing, support &amp;#x26; pricing:&lt;/strong&gt; The SDK is backed by Picsart’s large ecosystem and its AI research arm (PAIR), so teams can expect regular updates, new features, and scalable performance. Support comes through developer documentation, a support team, and enterprise collaboration options. Pricing isn’t public, but it’s likely offered as enterprise or usage‑based licensing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Who it’s for:&lt;/strong&gt; Picsart’s Video SDK is best for teams that need a web‑based video editor to power product features or educational video production without investing heavily in custom development.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-it-compares-to-imgly-5&quot;&gt;&lt;strong&gt;How it compares to IMG.LY&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Picsart offers a fast, embeddable editor with AI effects and a strong ecosystem. However, IMG.LY provides deeper customization, more automation capabilities, cross‑platform support, and enterprise‑grade integrations.&lt;/p&gt;
&lt;h2 id=&quot;overview-table-use-cases-vs-solutions&quot;&gt;&lt;strong&gt;Overview Table (Use Cases vs. Solutions)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Here is how the seven options line up on the four questions teams ask most often during an evaluation.&lt;/p&gt;





























































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;SDK&lt;/th&gt;&lt;th&gt;Best for&lt;/th&gt;&lt;th&gt;Platforms&lt;/th&gt;&lt;th&gt;Customization depth&lt;/th&gt;&lt;th&gt;Pricing model&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;IMG.LY CE.SDK&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;SaaS, MarTech, e-commerce and DAM platforms that need a user-facing editor and backend automation&lt;/td&gt;&lt;td&gt;Web, iOS, Android, React Native, Flutter, Electron, Node.js&lt;/td&gt;&lt;td&gt;Fully white-label, extensible through a plugin system&lt;/td&gt;&lt;td&gt;Usage-based&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Meishe (Meicam)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Large-scale apps in Asia with strong internal dev resources&lt;/td&gt;&lt;td&gt;Mobile, web, PC&lt;/td&gt;&lt;td&gt;Full UI customization, white-labeling and plugins, though integration is heavier&lt;/td&gt;&lt;td&gt;Enterprise licensing&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Banuba&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Mobile apps built around AR: beauty filters, face tracking, virtual try-on&lt;/td&gt;&lt;td&gt;iOS, Android, Flutter, React Native&lt;/td&gt;&lt;td&gt;Modular components with a preset UI, limited beyond that&lt;/td&gt;&lt;td&gt;Not public, typically high&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Shotstack&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Bulk rendering and automation pipelines rather than in-app editing&lt;/td&gt;&lt;td&gt;Cloud REST API&lt;/td&gt;&lt;td&gt;No prebuilt UI components, you build the editor yourself&lt;/td&gt;&lt;td&gt;Pay-as-you-go at $0.30 per minute, or subscription&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;BytePlus Effects&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Consumer apps recreating TikTok-style experiences from prebuilt AR effects&lt;/td&gt;&lt;td&gt;iOS, Android, React Native, Flutter&lt;/td&gt;&lt;td&gt;Theming to match your brand, limited past that&lt;/td&gt;&lt;td&gt;Enterprise negotiation with annual fees&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Rendley&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Browser-native, client-only editing with no server infrastructure&lt;/td&gt;&lt;td&gt;Browser (JavaScript)&lt;/td&gt;&lt;td&gt;Open in-browser approach, no enterprise-level frameworks&lt;/td&gt;&lt;td&gt;Not public&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Picsart Video SDK&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Web-first product, edu-tech and media teams that want a fast embed&lt;/td&gt;&lt;td&gt;React Native based, optimized for web embedding&lt;/td&gt;&lt;td&gt;Configurable UI, theming, white-label, feature toggles, own asset library&lt;/td&gt;&lt;td&gt;Not public, likely enterprise or usage-based&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;When you line these SDKs up side by side, it’s clear that each one has its own niche strengths and limitations. Here’s a quick overview:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Banuba / BytePlus:&lt;/strong&gt; These are the strongest options for AR and social apps, with beauty filters, effects, and TikTok-like workflows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Meishe:&lt;/strong&gt; A professional, Asia-centric SDK with heavy native capabilities, but a steeper implementation curve.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shotstack / Rendley:&lt;/strong&gt; Both shine in automation pipelines or lightweight browser-based setups, but they don’t offer polished editor UIs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Picsart:&lt;/strong&gt; A strong web-first, prebuilt editor with AI effects that’s simple to embed, though limited in customization and automation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;where-does-that-leave-you&quot;&gt;Where does that leave you?&lt;/h3&gt;
&lt;p&gt;If you’re evaluating SDKs, you need to balance two priorities: delivering a great editor UX for your users and scaling automation behind the scenes. Only IMG.LY covers both ends: offering a polished, enterprise-ready editor and a scalable automation engine.&lt;/p&gt;
&lt;p&gt;That makes it the go-to option for teams planning not only their current projects but also long-term growth. With IMG.LY, you can give users a polished editing experience today while building the automation backbone that will let your product scale tomorrow&lt;/p&gt;
&lt;p&gt;If you’d like to see how IMG.LY can fit into your platform, &lt;a href=&quot;https://img.ly/forms/contact-sales/&quot;&gt;get in touch with our experts today&lt;/a&gt; for a deeper look and tailored guidance.&lt;/p&gt;</content:encoded><dc:creator>Jan</dc:creator><media:content url="https://blog.img.ly/2025/09/top-video-editor-sdks-in-2025--1-.png" medium="image"/><category>Video Editor</category><category>Insights</category></item><item><title>A Modern JavaScript Video Editor: Integration Guide</title><link>https://img.ly/blog/a-modern-javascript-video-editor-integration-guide/</link><guid isPermaLink="true">https://img.ly/blog/a-modern-javascript-video-editor-integration-guide/</guid><description>Learn how to integrate IMG.LY&apos;s Javascript video editor into your web app and how to best leverage its capabilities.</description><pubDate>Thu, 16 Jan 2025 15:29:04 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Discover how to integrate&lt;/em&gt; &lt;a href=&quot;https://img.ly/docs/cesdk/js/starterkits/video-editor-e1nlor/&quot;&gt;&lt;em&gt;IMG.LY’s JavaScript video editor&lt;/em&gt;&lt;/a&gt; &lt;em&gt;into your web application and unlock its full range of features.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Video content has always been a powerhouse for engagement, becoming even more impactful with the rise of short-form videos. Platforms like YouTube and TikTok have built their empires on video content, as that remains the preferred medium for both creating and consuming information.&lt;/p&gt;
&lt;p&gt;Not only have those platforms changed how we consume information, but they have also transformed user behavior. We do not just want to watch videos. We want to create them, expecting the process to be both simple and professional.&lt;/p&gt;
&lt;p&gt;Here is why embedding video creation and editing capabilities directly into your website, web or mobile application can significantly boost user engagement and satisfaction.&lt;/p&gt;
&lt;p&gt;In this guide, you will learn how to integrate a JavaScript video editor using CreativeEditor SDK (CE.SDK). We will explore when it is most useful and what customizations it supports to suit your unique needs.&lt;/p&gt;
&lt;p&gt;Want to jump into the code? For a quick start, visit our &lt;a href=&quot;https://github.com/imgly/cesdk-web-examples/tree/showcases/integrate-with-vanilla-js&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let’s dive in!&lt;/p&gt;
&lt;h2 id=&quot;why-does-your-javascript-web-app-need-a-video-editor&quot;&gt;Why Does Your JavaScript Web App Need a Video Editor?&lt;/h2&gt;
&lt;p&gt;The world of content is constantly evolving, from text to images, from static visuals to long-form videos, and now from long videos to bite-sized clips. What stays consistent is that &lt;a href=&quot;https://www.idomoo.com/blog/surprising-video-engagement-statistics/&quot;&gt;video content resonates deeply with us as humans&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;No wonder, &lt;a href=&quot;https://www.statista.com/statistics/1285960/top-downloaded-mobile-apps-worldwide/&quot;&gt;TikTok tops global app download charts&lt;/a&gt;, while &lt;a href=&quot;https://www.similarweb.com/top-websites/&quot;&gt;YouTube, Facebook, and Instagram rank among the most visited sites&lt;/a&gt; right after Google. These platforms have not just built their empires on video. They have revolutionized how we think about video production.&lt;/p&gt;
&lt;p&gt;They set the gold standard by enabling anyone to create professional-looking videos with minimal effort, offering tools for adding filters, overlays, audio, and text in just a few clicks. This ease of use has made intuitive video editing a must-have for web applications featuring social media integration, marketing ambitions, or content management capabilities.&lt;/p&gt;
&lt;p&gt;By embedding a user-friendly JavaScript video editor in your application, you can ride this trend, providing a feature billions of users are already familiar with. The payoff? Lower barriers to user-generated content, enhanced engagement, and wider content distribution.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://img.ly/products/creative-sdk/&quot;&gt;CreativeEditor SDK&lt;/a&gt; from &lt;a href=&quot;https://IMG.LY&quot;&gt;IMG.LY&lt;/a&gt; delivers a seamless, high-performance, and feature-rich JavaScript solution for in-browser design, video, and photo editing, ready to meet your users’ expectations.&lt;/p&gt;
&lt;h2 id=&quot;getting-started-adding-a-video-editor-in-javascript&quot;&gt;Getting Started: Adding a Video Editor in JavaScript&lt;/h2&gt;
&lt;p&gt;Follow this step-by-step guide to learn how to integrate a JavaScript video editor into your site using CreativeEditor SDK.&lt;/p&gt;
&lt;p&gt;Get started with integrating CE.SDK in a vanilla JavaScript application!&lt;/p&gt;
&lt;h3 id=&quot;requirements&quot;&gt;Requirements&lt;/h3&gt;
&lt;p&gt;CreativeEditor SDK runs directly in your browser’s JavaScript engine, so no specific prerequisites are needed.&lt;/p&gt;
&lt;p&gt;If your web application relies on Node.js, ensure that you have the &lt;a href=&quot;https://nodejs.org/en/download&quot;&gt;latest stable versions of Node.js and NPM installed&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;installation-and-library-import&quot;&gt;Installation and Library Import&lt;/h3&gt;
&lt;p&gt;In a vanilla JavaScript application, create a JavaScript module file (e.g., video-editor.js) and import the CreativeEditorSDK library:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; CreativeEditorSDK &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;&amp;#x3C;https://cdn.img.ly/packages/imgly/cesdk-js/1.42.0/index.js&gt;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: In this example, the SDK is served from our CDN for convenience. In a production environment, you should &lt;a href=&quot;https://img.ly/docs/cesdk/js/serve-assets-b0827c/&quot;&gt;host assets on your own servers&lt;/a&gt; for improved control and performance.&lt;/p&gt;
&lt;p&gt;Alternatively, if you are using a bundler like Webpack, Rollup, Parcel, or Vite, and you want to integrate the CreativeEditor module within your existing project, simply add the &lt;a href=&quot;https://www.npmjs.com/package/@cesdk/cesdk-js&quot;&gt;@cesdk/cesdk-js&lt;/a&gt; npm package as a dependency to your project:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; [@cesdk/cesdk-js](&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;https://www.npmjs.com/package/@cesdk/cesdk-js&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can then import it as below:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; CreativeEditorSDK&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; &quot;@cesdk/cesdk-js&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well done!&lt;/p&gt;
&lt;h3 id=&quot;initialize-the-video-editor&quot;&gt;Initialize the Video Editor&lt;/h3&gt;
&lt;p&gt;In your JavaScript module, right below the library import, initialize CreativeEditor SDK with the following logic:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// src/video-editor.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; CreativeEditorSDK &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;&amp;#x3C;https://cdn.img.ly/packages/imgly/cesdk-js/1.42.0/index.js&gt;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// your CE.SDK license and user configs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  license: &lt;/span&gt;&lt;span&gt;&apos;&amp;#x3C;YOUR_LICENSE&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  userId: &lt;/span&gt;&lt;span&gt;&apos;&amp;#x3C;YOUR_USER_ID&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;CreativeEditorSDK.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;#cesdk_container&apos;&lt;/span&gt;&lt;span&gt;, config).&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;editor&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // do something with your instance of CreativeEditor SDK...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // when done, clean up and free up resources&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  editor.&lt;/span&gt;&lt;span&gt;dispose&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;&amp;#x3C;YOUR_LICENSE&gt;&lt;/code&gt; with the license key you get from CreativeEditor SDK and &lt;code&gt;&amp;#x3C;YOUR_USER_ID&gt;&lt;/code&gt; with your user ID. The user ID is optional and helps track MAUs (Monthly Active Users) across different devices.&lt;/p&gt;
&lt;p&gt;To integrate the video-editor.js file, import it into your HTML page like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;module&quot;&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;video-editor.js&quot;&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules&quot;&gt;type=“module”&lt;/a&gt; attribute. This tells the browser to treat the script as an ES6 module, so that you can use import and export statements within your JavaScript code.&lt;/p&gt;
&lt;p&gt;Make sure the same HTML page includes the following div element where the video editor will be embedded:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;cesdk_container&quot;&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;width: 100%; height: 100vh;&quot;&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will load the video editor with the default video preset, giving users the ability to trim, cut, apply filters, add text overlays, include music, and more to enhance their videos.&lt;/p&gt;
&lt;p&gt;Congratulations, you have successfully integrated the video editor!&lt;/p&gt;
&lt;h2 id=&quot;creativeeditor-sdk-javascript-video-editing-api-for-web-desktop-and-mobile&quot;&gt;CreativeEditor SDK: JavaScript Video Editing API for Web, Desktop, and Mobile&lt;/h2&gt;
&lt;p&gt;You just saw how to integrate the CE.SDK into a browser application. Yet, do not forget that the SDK supports a wide variety of frameworks and libraries, including mobile and web applications.&lt;/p&gt;
&lt;h3 id=&quot;web-framework-support&quot;&gt;Web Framework Support&lt;/h3&gt;
&lt;p&gt;CE.SDK is designed to work with several popular JavaScript frameworks and libraries. For more detailed integration instructions, take a look at the official page on the documentation for each framework:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/react/get-started/overview-e18f40/&quot;&gt;React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/angular/get-started/overview-e18f40/&quot;&gt;Angular&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/vue/get-started/overview-e18f40/&quot;&gt;Vue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/svelte/get-started/overview-e18f40/&quot;&gt;Svelte&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/js/get-started/overview-e18f40/&quot;&gt;JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, the SDK is available for headless mode and works well in a &lt;a href=&quot;https://img.ly/docs/cesdk/node/get-started/overview-e18f40/&quot;&gt;Node.js environment&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;cross-platform-support&quot;&gt;Cross-Platform Support&lt;/h3&gt;
&lt;p&gt;One of the standout features of CreativeEditor SDK is its cross-platform philosophy. This extends beyond JavaScript ecosystems for the web, and includes mobile (iOS and Android) and desktop, thanks to support for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/react-native/get-started/overview-e18f40/&quot;&gt;React Native&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/electron/get-started/overview-e18f40/&quot;&gt;Electron&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is made possible through a powerful engine that powers your app via features like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unified API&lt;/strong&gt;: The same underlying API is shared across web, desktop, iOS, and Android applications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-Platform Feature Parity&lt;/strong&gt;: CE.SDK guarantees that features are available consistently across platforms. Since core functionality is implemented at the engine level, features you use on one platform will be available on others, with only slight differences in release timelines.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interoperable Designs&lt;/strong&gt;: Designs created in the editor component on one platform work on all platforms supported by CE.SDK. Whether a user is designing on iOS, Android, or the web, their design files can be imported seamlessly between platforms.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Native iOS and Android libraries, along with other frameworks, are also available. &lt;a href=&quot;https://img.ly/docs/cesdk/&quot;&gt;Learn more in our documentation!&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;javascript-video-editor-use-cases&quot;&gt;JavaScript Video Editor Use Cases&lt;/h2&gt;
&lt;p&gt;It is time to explore some key use cases. Let’s see how the unique features of the CreativeEditor SDK can cover many scenarios!&lt;/p&gt;
&lt;h3 id=&quot;social-media-publishing&quot;&gt;Social Media Publishing&lt;/h3&gt;
&lt;p&gt;CreativeEditor SDK features what users need to create engaging and easy-to-share videos optimized for popular social media platforms like Instagram, TikTok, YouTube, LinkedIn, and more. This is possible due to a large set of capabilities, which include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reusable Templates&lt;/strong&gt;: Users can either design their own templates and share them with the community or download those created by others. This variety of ready-to-use templates for different scenarios helps users skip the daunting blank canvas to bring their ideas to life. Explore various templates in our &lt;a href=&quot;https://img.ly/demos/video-ui/web/&quot;&gt;video editor demo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Music and Audio Library&lt;/strong&gt;: In CE.SDK, adding audio to videos is simple and intuitive. Given the impact of audio, users can set the tone with music or narration in just a few clicks, creating a more immersive atmosphere for their content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Animations&lt;/strong&gt;: The SDK includes a &lt;a href=&quot;https://img.ly/docs/cesdk/js/animation/overview-6a2ef2/&quot;&gt;wide selection of animations&lt;/a&gt; to enhance the design elements positioned within video scenes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After creating a video within your web app, users can export it directly from CE.SDK in the appropriate formats and aspect ratios for their target social media platforms.&lt;/p&gt;
&lt;h3 id=&quot;product-showcase-for-e-commerce-applications&quot;&gt;Product Showcase for E-Commerce Applications&lt;/h3&gt;
&lt;p&gt;Images have long been a simple yet powerful tool for showcasing products on e-commerce platforms, and sites like eBay, Amazon, AliExpress, and Walmart have relied on them for years (and still do!).&lt;/p&gt;
&lt;p&gt;However, in recent years, customer expectations have shifted. Today’s buyers crave more interactive and immersive ways to visualize products. They want to see how items look and perform in real-world settings.&lt;/p&gt;
&lt;p&gt;Short, dynamic product videos offer a superior presentation experience. According to &lt;a href=&quot;https://www.retaildive.com/spons/the-future-of-e-commerce-is-video-5-undeniable-consumer-stats/711062/&quot;&gt;an analysis by Firework&lt;/a&gt;, video content increases purchase likelihood by 51%, highlighting its undeniable impact on buying decisions. This is why many sellers have already embraced video to enhance product displays.&lt;/p&gt;
&lt;p&gt;With a CE.SDK-powered JavaScript video editor, producing compelling videos that deliver a seamless, multi-device shopping experience becomes effortless. Plus, reusable templates help you generate unique product videos while maintaining brand consistency.&lt;/p&gt;
&lt;h3 id=&quot;engaging-video-messages-for-sales-outreach&quot;&gt;Engaging Video Messages for Sales Outreach&lt;/h3&gt;
&lt;p&gt;Marketers and sales teams know that cold emails often come across as impersonal and boring. The solution to this challenge? Personalized video messages!&lt;/p&gt;
&lt;p&gt;Customized video messages are proving to be an effective outreach tool, with studies showing &lt;a href=&quot;https://www.tavus.io/post/video-marketing-statistics&quot;&gt;significantly higher conversion rates&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With CreativeEditor SDK, sales and marketing teams can easily create personalized videos tailored to individual clients or leads, making their outreach more engaging and impactful. Unlike traditional email campaigns, personalized videos create a sense of real, one-on-one interaction.&lt;/p&gt;
&lt;p&gt;Additionally, the SDK’s translation features help sales teams break down language barriers, allowing them to reach a global audience. This ensures that the personalized messages resonate with clients from different regions.&lt;/p&gt;
&lt;p&gt;Explore this feature in our &lt;a href=&quot;https://img.ly/demos/language/web/&quot;&gt;translation and internationalization demo&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;digital-asset-management&quot;&gt;Digital Asset Management&lt;/h3&gt;
&lt;p&gt;DAM, short for &lt;a href=&quot;https://www.ibm.com/think/topics/digital-asset-management&quot;&gt;Digital Asset Management&lt;/a&gt;, is the process of organizing, storing, and managing digital assets, including video content. As your business grows, an effective DAM system becomes key to enabling multiple teams to easily access and collaborate on assets across different projects.&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK backs DAM workflows by offering powerful tools to organize, edit, and repurpose video content through an embeddable, centralized interface. Its core JavaScript video editor component empowers users to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Effortlessly adapt and customize video assets.&lt;/li&gt;
&lt;li&gt;Ensure brand consistency while automating updates across various assets.&lt;/li&gt;
&lt;li&gt;Edit content efficiently within a collaborative environment.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Although CE.SDK does not provide built-in role-based permissions, it integrates smoothly with backend systems to control user access. In particular, its flexible architecture supports the definition of custom hooks for permission checks to customize the editor’s behavior.&lt;/p&gt;
&lt;h3 id=&quot;automated-video-creation&quot;&gt;Automated Video Creation&lt;/h3&gt;
&lt;p&gt;CreativeEditor SDK streamlines the automation of asset creation by enabling users to generate on-brand video content variations for multiple channels. Thanks to adaptable templates, &lt;a href=&quot;https://img.ly/docs/cesdk/js/create-templates/add-dynamic-content/text-variables-7ecb50/&quot;&gt;dynamic text variables&lt;/a&gt;, and lockable designs, the SDK ensures consistency and brand compliance over all produced videos.&lt;/p&gt;
&lt;p&gt;Given a template, the creative engine automates the generation of countless personalized assets by populating them with resources from various data sources. That eliminates manual effort, reduces design bottlenecks, and accelerates production, making it perfect for scaling campaign-specific videos or building dedicated &lt;a href=&quot;https://img.ly/industries/marketing-tech/&quot;&gt;marketing tech&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;customizing-your-creativeeditor-sdk-instance&quot;&gt;Customizing your CreativeEditor SDK Instance&lt;/h2&gt;
&lt;p&gt;CreativeEditor SDK is not a one-size-fits-all JavaScript video editor. Instead, it is built for flexibility, offering a wide set of customization options to tailor the editor to your unique requirements and brand identity. These include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Theming Options&lt;/strong&gt;: Match the editor’s look to your app’s style with built-in themes, generate new ones using the &lt;a href=&quot;https://img.ly/docs/cesdk/js/user-interface/appearance/theming-4b0938/#using-the-theme-generator&quot;&gt;theme generator&lt;/a&gt;, or create custom themes manually. Explore theming possibilities in our &lt;a href=&quot;https://img.ly/demos/theming/web/&quot;&gt;dedicated demo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom UI&lt;/strong&gt;: Build entirely bespoke JavaScript video editing user interfaces that align with your specific use case.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Media Library Integration&lt;/strong&gt;: Set up sortable, flexible media libraries and integrate popular third-party libraries like &lt;a href=&quot;https://img.ly/demos/unsplash-image-assets/web/&quot;&gt;Unsplash and others&lt;/a&gt;. Get easy access to external assets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Localization&lt;/strong&gt;: Adapt the editor to different languages and regions with &lt;a href=&quot;https://img.ly/docs/cesdk/js/user-interface/localization-508e20/&quot;&gt;full i18n support&lt;/a&gt;, letting you extend or overwrite any language setting.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Toolbar Customization&lt;/strong&gt;: Rearrange toolbar elements, update icons, or rename tools to deliver a tailored user experience.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With these customization options, CreativeEditor SDK ensures your video editor is as unique as your JavaScript application.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Implementing a JavaScript video editor in your web app can greatly improve the user experience and provide a powerful feature to drive higher engagement, retention, and even product distribution. This is true whether you are developing an e-commerce platform, a social media app, a tool for influencers, or a SaaS web solution.&lt;/p&gt;
&lt;p&gt;With the CreativeEditor SDK, adding a fully customizable video editing experience to your web application takes only a few minutes. Explore CE.SDK’s video capabilities and &lt;a href=&quot;https://img.ly/docs/cesdk/flutter/prebuilt-solutions/video-editor-9e533a/&quot;&gt;dive into the docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Stay tuned for more updates, and please &lt;a href=&quot;https://img.ly/forms/contact-sales/&quot;&gt;reach out&lt;/a&gt; if you have any questions. Thank you for reading.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Over 3,000 creative professionals gain early access to our new features, demos, and updates. Don’t miss out, and&lt;/strong&gt; &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i?ref=img.ly&quot;&gt;&lt;strong&gt;subscribe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to our newsletter.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2025/01/video-editor-javascript.jpg" medium="image"/><category>JavaScript</category><category>Video Editor</category><category>CE.SDK</category></item><item><title>How I Built a Short Video Generator with AI &amp; CE.SDK in One Day</title><link>https://img.ly/blog/how-to-build-short-video-generator-ai-creative-sdk/</link><guid isPermaLink="true">https://img.ly/blog/how-to-build-short-video-generator-ai-creative-sdk/</guid><description>Can AI really accelerate product development? I built a short video generator in one day using AI and CE.SDK to find out.</description><pubDate>Thu, 09 Jan 2025 11:27:13 GMT</pubDate><content:encoded>&lt;p&gt;Here’s the crux of product development in the age of LLMs: how much can AI truly accelerate the development process?&lt;/p&gt;
&lt;p&gt;We have seen videos of solo developers building small apps entirely with AI with just a few prompts. But how does it scale to more complex development projects? As LLMs rapidly evolve, their scope and impact will only increase.&lt;/p&gt;
&lt;p&gt;That’s why I regularly challenge myself to build a small project with the help of AI. I’m a prime candidate to test the AI productivity boost: a jack-of-all-trades (and a master of none) with a background in both design and engineering, yet no hands-on experience in the past five years. My latest challenge? Build a web-based short video generator within one day.&lt;/p&gt;
&lt;p&gt;In this post, I’ll share the most intriguing takeaways from tackling this project.&lt;/p&gt;
&lt;h2 id=&quot;why-a-short-video-generator&quot;&gt;Why a Short Video Generator?&lt;/h2&gt;
&lt;p&gt;Why focus on this idea? It’s simple: to ride the wave of a new trend. A format called “&lt;strong&gt;faceless&lt;/strong&gt;” short videos is gaining traction among creators on platforms like YouTube and TikTok.&lt;/p&gt;
&lt;figure class=&quot;kg-embed-card&quot;&gt;
&lt;iframe src=&quot;https://www.youtube.com/embed/DfQ3fhqfKVc?feature=oembed&quot; title=&quot;FUNNY USA Stereotype Records! #shorts&quot; loading=&quot;lazy&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/figure&gt;
&lt;p&gt;What’s fascinating about these videos is their automation: an LLM generates a script, which is then transformed into speech, images, and text assets using various AI services. These assets are automatically assembled into a cohesive video.&lt;/p&gt;
&lt;p&gt;The general concept is compelling: It’s still generative content, but mixed with classic video composition techniques. This approach offers greater accuracy, consistency, and control over pure generative AI.&lt;/p&gt;
&lt;p&gt;The potential to automate video production at this scale is exciting. Add its relatively low complexity and high production value, and it became the perfect topic for my challenge.&lt;/p&gt;
&lt;h2 id=&quot;enter-cesdk&quot;&gt;Enter CE.SDK&lt;/h2&gt;
&lt;p&gt;Another reason I chose this challenge was its compatibility with CE.SDK, our design and video editor library. CE.SDK offers a robust editing toolkit that integrates into any product with just a few lines of code. Its features, like headless mode, are ideal for automating workflows like video generation.&lt;/p&gt;
&lt;p&gt;Most faceless video services use React-based video generation and achieve fair results. However, using CE.SDK instead of a react-based library could potentially boost the overall experience with three critical improvements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Editable Outputs:&lt;/strong&gt; This is huge. Full automation often needs human adjustments for fine-tuning. CE.SDK enables automated video generation while allowing manual refinement of the results.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enhanced Visual Quality:&lt;/strong&gt; CE.SDK has its own rendering pipeline, allowing for more nuanced visual effects and animations. When you’re competing against others in this space, it can make a huge difference if you’re able to produce higher fidelity in the visual output.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visual Design Workflow:&lt;/strong&gt; Create design components or even entire templates visually, and then use them via code. This authoring workflow can be extremely helpful in creating rich, interesting designs for the generated videos.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-ground-rules&quot;&gt;The Ground Rules&lt;/h2&gt;
&lt;p&gt;To keep the challenge focused, I set strict rules:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Time Limit:&lt;/strong&gt; Spend no more than 12 hours on the challenge.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No Manual Coding:&lt;/strong&gt; Avoid writing any code yourself. Everything should be built through conversations with AI.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trust the AI:&lt;/strong&gt; Do not read or analyze code generated by the AI. Rely entirely on its decisions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Skip External Research:&lt;/strong&gt; Do not read or explore the APIs you intend to use. Instead, provide links to the AI and let it determine how to use them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compare AI Performance:&lt;/strong&gt; Alternate Claude Sonnet 3.5 and ChatGPT o1 for code generation to evaluate which performs better.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;the-tools--workflow&quot;&gt;The Tools &amp;#x26; Workflow&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Code Editor:&lt;/strong&gt; &lt;a href=&quot;https://www.cursor.com/&quot;&gt;&lt;strong&gt;Cursor&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
Built on VSCode’s foundation, Cursor stood out as the only editor offering both an integrated chat interface and the ability to switch between different LLMs. However, with GitHub’s recent significant updates to Copilot, I’ll switch to VSCode with Copilot for future challenges.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UI Prototyping:&lt;/strong&gt; &lt;a href=&quot;https://madewithclaude.com/&quot;&gt;&lt;strong&gt;Claude Artifacts&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
Rather than building the entire project in my code editor, I chose to prototype the UI directly through Claude’s web interface. The benefits were immense:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Instant results:&lt;/strong&gt; To create an artifact, Claude streamlines development by automatically writing and compiling code while leveraging essential UI libraries and components. This automation eliminates setup time and technical overhead, allowing me to focus purely on design iterations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Instants Variations:&lt;/strong&gt; Claude enables rapid prototyping through parallel conversations. When a design direction didn’t quite work, I could simply start a fresh conversation with modified requirements and evaluate a new prototype. This approach helped me develop three viable concepts quickly - a pace that would have been impossible in a traditional code editor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quality of execution:&lt;/strong&gt; Claude transforms rough concepts into polished, intuitive interfaces. Its suggestions often surpassed my initial ideas, offering sophisticated solutions I hadn’t considered.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep it clean:&lt;/strong&gt; By prototyping outside the code editor, I kept the main project’s codebase clean and focused. This separation prevented the accumulation of experimental code and maintained the clarity of our primary development environment.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/how-to/er-ai/0108.mp4&quot; controls loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Quickly prototype your interface with Claude Artifacts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;APIs&lt;/strong&gt;&lt;br&gt;
Key APIs used in the project included:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Script Generation:&lt;/strong&gt; Claude Sonnet 3.5 vs various ChatGPT models.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Image/Video Assets:&lt;/strong&gt; &lt;a href=&quot;https://Fal.ai&quot;&gt;Fal.ai&lt;/a&gt; Flux models.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Speech Synthesis:&lt;/strong&gt; &lt;a href=&quot;https://elevenlabs.io/&quot;&gt;ElevenLabs&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;building-the-app-divide-and-conquer&quot;&gt;Building the App: Divide and Conquer&lt;/h2&gt;
&lt;p&gt;After having prototyped the UI, I started to chat with the LLM inside the code editor so that it can code the app. To work with the AI efficiently, I followed a divide-and-conquer approach. Rather than simply asking it to “build me a video app,” I broke down the problem into manageable steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Generate a video script&lt;/strong&gt;&lt;br&gt;
Create an AI prompt that includes user input and examples of the desired output format. Pass this prompt to the LLM API.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parse the script to generate assets (speech, images, text)&lt;/strong&gt;&lt;br&gt;
Parse the LLM’s response to extract image prompts and speech paragraphs. Send these to their respective APIs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compose the final video&lt;/strong&gt;&lt;br&gt;
Load all the generated assets into a predefined template to generate the finished video through the CE.SDK library.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After completing these steps, I was finally able to generate my first fully automated videos! With a few more tweaks and additions, I had an MVP ready within twelve hours.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/how-to/er-ai/shortyroll.mp4&quot; controls loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;The final result: A Short Video Generator&lt;/p&gt;
&lt;p&gt;There are still some missing features, partly because I spent a significant amount of time refining the prompt to generate the video script. I also had to bend the rules occasionally: sometimes the LLM would hit a wall, and I had to read or write small snippets of code.&lt;/p&gt;
&lt;h2 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Engineering Knowledge Is Essential&lt;/strong&gt;&lt;br&gt;
You should have some engineering background to achieve the AI productivity boost in development.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI doesn’t solve everything for you. You are still the architect. You provide a lot of input and guidance. AI often needs to be pointed to the right strategy. Foundational knowledge of computer science is hugely advantageous for working with AI effectively.&lt;/li&gt;
&lt;li&gt;As mentioned, I had to read and write a few lines of code myself. Without coding experience, I would have probably not been able to progress, as the LLM was not able to.&lt;/li&gt;
&lt;li&gt;The getting started experience is nowhere close to novice-friendly. How do you get started with a new project in a code editor that actually requires you to do the setup manually? My workaround was to create an empty project, and then ask the LLM to instruct me to use a boilerplate for react. Again, this is engineering knowledge, any novice would have hit a wall already at this point.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Claude Outperformed ChatGPT&lt;/strong&gt;&lt;br&gt;
Claude was a clear winner in the side-by-side comparison, because of three reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Claude Artifacts was a game changer for UI prototyping.&lt;/li&gt;
&lt;li&gt;It was generally better at writing and understanding code. Difficult to quantify, but in some cases Claude fixed the mess ChatGPT left in the code&lt;/li&gt;
&lt;li&gt;Claude can process URLs, which makes working with APIs much smoother.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Who would have thought new LLMs would catch up to OpenAI so quickly after they released the first version of ChatGPT?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Complexity Slows AI&lt;/strong&gt;&lt;br&gt;
The more code in my project, the slower the overall progress. LLMs struggled with the growing complexity. Their context windows filled more quickly, and their responses became increasingly unreliable. At some point, it becomes extremely difficult to make architectural changes, especially if this affects multiple parts of the app. When trying to fix errors, you’ll often find yourself in a whack-a-mole game. While the AI would resolve one issue, it would inadvertently introduce new problems elsewhere, creating an endless loop of fixes and regressions.&lt;/p&gt;
&lt;p&gt;Ultimately, the time invested in this challenge was well worth it. While LLMs can’t build products end to end on their own, they can significantly streamline product development when paired with the right human collaboration. The real question is whether development teams are ready to adapt their habits and explore new workflows to boost productivity.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;This challenge has inspired me to refine and expand on this project. Future iterations will focus on harnessing CE.SDK’s unique features to push the boundaries of automated video generation.&lt;/p&gt;
&lt;p&gt;Stay tuned for part two of this series. There’s much more to explore!&lt;/p&gt;
&lt;p&gt;UPDATE: Read &lt;a href=&quot;https://img.ly/blog/how-to-build-a-short-video-generator-using-ce-sdk-2/&quot;&gt;part two&lt;/a&gt; - a cookbook how to build your own short video creator!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Over 3,000 creative professionals gain early access to our new features, insights and updates. Don’t miss out, and&lt;/strong&gt; &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i?ref=img.ly&quot;&gt;&lt;strong&gt;subscribe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to our newsletter.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Eray</dc:creator><media:content url="https://blog.img.ly/2025/01/build-ai-video-generator-1.jpg" medium="image"/><category>How-To</category><category>AI</category><category>CE.SDK</category><category>Artificial Intelligence</category><category>Video Editor</category></item><item><title>A Modern Vue.js Video Editor: Setup Guide</title><link>https://img.ly/blog/a-modern-vue-js-video-editor/</link><guid isPermaLink="true">https://img.ly/blog/a-modern-vue-js-video-editor/</guid><description>Learn how to integrate IMG.LY&apos;s video editor for Vue.js into your web app, from the first single-file component to timeline edits and MP4 export.</description><pubDate>Wed, 08 Jan 2025 11:24:43 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Discover how to integrate&lt;/em&gt; &lt;a href=&quot;https://img.ly/docs/cesdk/vue/starterkits/video-editor-e1nlor/&quot;&gt;&lt;em&gt;IMG.LY’s video editor&lt;/em&gt;&lt;/a&gt; &lt;em&gt;into your Vue.js application.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Users who trim and caption clips every day in TikTok or CapCut expect to do the same inside your product. When they cannot, they export, edit somewhere else, and upload again. That round trip is where people drop out of the workflow and where your assets stop being yours to template or version.&lt;/p&gt;
&lt;p&gt;This guide covers adding a video editor to a Vue.js app with CreativeEditor SDK (CE.SDK): the component, the timeline and export APIs underneath it, and the customization points that come up once it runs.&lt;/p&gt;
&lt;h2 id=&quot;check-browser-support-before-you-scope-the-work&quot;&gt;Check browser support before you scope the work&lt;/h2&gt;
&lt;p&gt;CE.SDK’s video mode encodes and decodes in the browser through the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebCodecs_API&quot;&gt;WebCodecs API&lt;/a&gt;. That is what makes client-side MP4 export possible without a render backend, and it is also the constraint. Video mode requires a recent Chromium browser: Chrome, Edge, Opera, Arc, and Brave all work. Safari and Firefox do not currently support video editing.&lt;/p&gt;
&lt;p&gt;Design and photo editing run everywhere, so this only limits the video path. If a large share of your traffic is on Safari, plan a fallback message now rather than during QA.&lt;/p&gt;
&lt;h2 id=&quot;why-put-the-editor-inside-the-app&quot;&gt;Why put the editor inside the app&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.youtube/inside-youtube/shorts-revenue-sharing-update/&quot;&gt;YouTube Shorts passes 70 billion daily views&lt;/a&gt; and TikTok reports &lt;a href=&quot;https://newsroom.tiktok.com/en-us/1-billion-people-on-tiktok&quot;&gt;more than a billion monthly active users&lt;/a&gt;. Those numbers matter here for one reason: they set the baseline for how easy people think video editing should be.&lt;/p&gt;
&lt;p&gt;Two things follow. Users expect filters, overlays, audio, and text within a few clicks, and they expect it where they already are. Vue’s single-file components suit this well, because the editor becomes one component you mount with a config object and an init hook.&lt;/p&gt;
&lt;h2 id=&quot;how-to-integrate-a-video-editor-in-vuejs&quot;&gt;How to integrate a video editor in Vue.js&lt;/h2&gt;
&lt;h3 id=&quot;requirements&quot;&gt;Requirements&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Node.js 20+ and npm 10+. &lt;a href=&quot;https://nodejs.org/download&quot;&gt;Download Node.js&lt;/a&gt; if needed.&lt;/li&gt;
&lt;li&gt;A Vue 3 project, typically scaffolded with &lt;a href=&quot;https://github.com/vuejs/create-vue&quot;&gt;create-vue&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A CE.SDK license key. &lt;a href=&quot;https://img.ly/docs/cesdk/&quot;&gt;Start a free trial&lt;/a&gt; to get one.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you need a project, scaffold one and answer the prompts however you like. Selecting “No” throughout is fine for following along:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; vue@latest&lt;/span&gt;&lt;span&gt; my-vue-video-editor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; my-vue-video-editor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-1-install-cesdk&quot;&gt;Step 1: Install CE.SDK&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; @cesdk/cesdk-js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-2-create-the-editor-component&quot;&gt;Step 2: Create the editor component&lt;/h3&gt;
&lt;p&gt;CE.SDK ships a Vue component, so you do not manage the editor instance or its teardown yourself. Import it from the &lt;code&gt;/vue&lt;/code&gt; entry point and give it a &lt;code&gt;config&lt;/code&gt; object and an &lt;code&gt;init&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Create &lt;code&gt;src/components/VideoEditor.vue&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;!-- src/components/VideoEditor.vue --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;&lt;/span&gt;&lt;span&gt;CreativeEditor&lt;/span&gt;&lt;span&gt; :config&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;config&quot;&lt;/span&gt;&lt;span&gt; :init&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;init&quot;&lt;/span&gt;&lt;span&gt; width&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;100vw&quot;&lt;/span&gt;&lt;span&gt; height&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;100vh&quot;&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt; setup&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; CreativeEditor &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@cesdk/cesdk-js/vue&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  license: &lt;/span&gt;&lt;span&gt;&apos;YOUR_LICENSE_KEY&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// replace with your key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  userId: &lt;/span&gt;&lt;span&gt;&apos;YOUR_USER_ID&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// optional, for MAU tracking across devices&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; async&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;cesdk&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  await&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;all&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    cesdk.&lt;/span&gt;&lt;span&gt;addDefaultAssetSources&lt;/span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    cesdk.&lt;/span&gt;&lt;span&gt;addDemoAssetSources&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      sceneMode: &lt;/span&gt;&lt;span&gt;&apos;Video&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      withUploadAssetSources: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  await&lt;/span&gt;&lt;span&gt; cesdk.&lt;/span&gt;&lt;span&gt;createVideoScene&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sceneMode: &apos;Video&apos;&lt;/code&gt; loads the video and audio demo libraries instead of the design ones, so the asset panel holds clips and music. In production you swap these for your own sources, whether that is your backend or a third-party library such as &lt;a href=&quot;https://img.ly/docs/cesdk/vue/import-media/from-remote-source/unsplash-8f31f0/&quot;&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;createVideoScene()&lt;/code&gt; is what gives you the timeline. Calling &lt;code&gt;createDesignScene()&lt;/code&gt; instead produces the design editor with no time dimension, which is the usual reason a first integration loads without a timeline.&lt;/p&gt;
&lt;h3 id=&quot;step-3-use-the-component&quot;&gt;Step 3: Use the component&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;vue&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;!-- src/App.vue --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;&lt;/span&gt;&lt;span&gt;VideoEditor&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt; setup&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; VideoEditor &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./components/VideoEditor.vue&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run &lt;code&gt;npm run dev&lt;/code&gt;. You should get a full editor with a timeline: trimming, splitting, text overlays, audio tracks, and filters.&lt;/p&gt;
&lt;p&gt;Name your wrapper something other than &lt;code&gt;CreativeEditor&lt;/code&gt;, or it will collide with the imported component.&lt;/p&gt;
&lt;h2 id=&quot;gotchas-worth-knowing-up-front&quot;&gt;Gotchas worth knowing up front&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;init&lt;/code&gt; fails silently.&lt;/strong&gt; If a line inside &lt;code&gt;init&lt;/code&gt; throws, the rest is skipped and nothing reaches the console. You get a half-built scene with no error. Wrap it while developing:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; async&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;cesdk&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  try&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    await&lt;/span&gt;&lt;span&gt; cesdk.&lt;/span&gt;&lt;span&gt;addDefaultAssetSources&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    await&lt;/span&gt;&lt;span&gt; cesdk.&lt;/span&gt;&lt;span&gt;createVideoScene&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  } &lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt; (error) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;[CE.SDK init] failed:&apos;&lt;/span&gt;&lt;span&gt;, error);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Relative asset URLs resolve against the CDN.&lt;/strong&gt; CE.SDK resolves relative URIs against &lt;code&gt;config.baseURL&lt;/code&gt;, which points at the IMG.LY CDN, so &lt;code&gt;/videos/intro.mp4&lt;/code&gt; will not hit your origin. Make local paths absolute before passing them to the engine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trim calls need loaded media.&lt;/strong&gt; &lt;code&gt;setTrimOffset&lt;/code&gt; and &lt;code&gt;setTrimLength&lt;/code&gt; depend on duration metadata. Call &lt;code&gt;await engine.block.forceLoadAVResource(fill)&lt;/code&gt; first or they quietly do nothing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nuxt needs a client-only boundary.&lt;/strong&gt; The editor is browser-only, so server-side rendering will break it. Wrap it in &lt;code&gt;&amp;#x3C;ClientOnly&gt;&lt;/code&gt; or use a &lt;code&gt;.client.vue&lt;/code&gt; component.&lt;/p&gt;
&lt;h2 id=&quot;let-an-agent-do-the-integration&quot;&gt;Let an agent do the integration&lt;/h2&gt;
&lt;p&gt;If you work in an AI-assisted editor, &lt;a href=&quot;https://img.ly/docs/cesdk/vue/get-started/agent-skills-f7g8h9/&quot;&gt;Agent Skills for CE.SDK&lt;/a&gt; load the current documentation and conventions into Claude Code, Cursor, and similar tools, so the generated integration matches the current API rather than a remembered one. There is also an &lt;a href=&quot;https://img.ly/docs/cesdk/vue/get-started/mcp-server-fde71c/&quot;&gt;MCP server&lt;/a&gt; for live doc lookup during a session. We wrote about the reasoning in &lt;a href=&quot;https://img.ly/blog/img-ly-agent-skills-web/&quot;&gt;Introducing IMG.LY Agent Skills&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;building-compositions-in-code&quot;&gt;Building compositions in code&lt;/h2&gt;
&lt;p&gt;The default UI handles user-facing editing. For templates, automation, or a custom interface, work through &lt;code&gt;cesdk.engine&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;create-a-scene-and-a-page&quot;&gt;Create a scene and a page&lt;/h3&gt;
&lt;p&gt;In video mode a page owns a timeline, and its duration is the duration of the export.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; engine&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; cesdk.engine;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; scene&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.scene.&lt;/span&gt;&lt;span&gt;createVideo&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; page&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;page&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(scene, page);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setWidth&lt;/span&gt;&lt;span&gt;(page, &lt;/span&gt;&lt;span&gt;1280&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setHeight&lt;/span&gt;&lt;span&gt;(page, &lt;/span&gt;&lt;span&gt;720&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setDuration&lt;/span&gt;&lt;span&gt;(page, &lt;/span&gt;&lt;span&gt;20&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// seconds&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;add-clips&quot;&gt;Add clips&lt;/h3&gt;
&lt;p&gt;Video is not a block type of its own. You create a &lt;code&gt;graphic&lt;/code&gt; block and attach a video fill, so the same positioning and animation APIs apply to video as to anything else.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; clip&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;graphic&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setShape&lt;/span&gt;&lt;span&gt;(clip, engine.block.&lt;/span&gt;&lt;span&gt;createShape&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;rect&apos;&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; fill&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;createFill&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;video&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  fill,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;fill/video/fileURI&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;https://cdn.img.ly/assets/demo/v3/ly.img.video/videos/pexels-drone-footage-of-a-surfer-barrelling-a-wave-12715991.mp4&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setFill&lt;/span&gt;&lt;span&gt;(clip, fill);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;sequence-with-a-track&quot;&gt;Sequence with a track&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;track&lt;/code&gt; keeps its children playing back to back and recalculates offsets when a duration changes, so you do not position clips by hand.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; track&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;track&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(page, track);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(track, clip1);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(track, clip2);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;fillParent&lt;/span&gt;&lt;span&gt;(track);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setDuration&lt;/span&gt;&lt;span&gt;(clip1, &lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// track shifts clip2 automatically&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Size the children, not the track. A track derives its dimensions from what it contains.&lt;/p&gt;
&lt;h3 id=&quot;trim-and-audio&quot;&gt;Trim and audio&lt;/h3&gt;
&lt;p&gt;Blocks default to 5 seconds. A longer clip gets cut off, a shorter one loops.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;forceLoadAVResource&lt;/span&gt;&lt;span&gt;(fill);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setTrimOffset&lt;/span&gt;&lt;span&gt;(fill, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// skip the first second&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setTrimLength&lt;/span&gt;&lt;span&gt;(fill, &lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setMuted&lt;/span&gt;&lt;span&gt;(fill, &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; audio&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;audio&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(page, audio);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  audio,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;audio/fileURI&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;https://cdn.img.ly/assets/demo/v3/ly.img.audio/audios/far_from_home.m4a&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setVolume&lt;/span&gt;&lt;span&gt;(audio, &lt;/span&gt;&lt;span&gt;0.7&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setTimeOffset&lt;/span&gt;&lt;span&gt;(audio, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;export-to-mp4&quot;&gt;Export to MP4&lt;/h3&gt;
&lt;p&gt;Encoding runs in a background worker, so the editor stays usable. The scene freezes when the export starts, so later edits will not show up in the file.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; page&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.scene.&lt;/span&gt;&lt;span&gt;getCurrentPage&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; blob&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;exportVideo&lt;/span&gt;&lt;span&gt;(page, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  mimeType: &lt;/span&gt;&lt;span&gt;&apos;video/mp4&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  onProgress&lt;/span&gt;&lt;span&gt;: (&lt;/span&gt;&lt;span&gt;rendered&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;encoded&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;total&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    progress.value &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; Math.&lt;/span&gt;&lt;span&gt;round&lt;/span&gt;&lt;span&gt;((encoded &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; total) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; anchor&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;a&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;anchor.href &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; URL&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;createObjectURL&lt;/span&gt;&lt;span&gt;(blob);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;anchor.download &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;export.mp4&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;anchor.&lt;/span&gt;&lt;span&gt;click&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Bind &lt;code&gt;onProgress&lt;/code&gt; to a ref and you have a progress bar. Long compositions take a while to encode, and silence reads as a hang.&lt;/p&gt;
&lt;p&gt;You can also extract just the audio with &lt;code&gt;engine.block.exportAudio(page, { mimeType: &apos;audio/wav&apos; })&lt;/code&gt;, which is handy for transcription and caption pipelines. Speaking of which, &lt;a href=&quot;https://img.ly/docs/cesdk/vue/create-video/update-caption-presets-e9c385/&quot;&gt;caption presets&lt;/a&gt; and &lt;a href=&quot;https://img.ly/docs/cesdk/vue/create-video/apply-transitions-146026/&quot;&gt;transitions between clips&lt;/a&gt; are both worth a look once the basics work.&lt;/p&gt;
&lt;p&gt;Full reference: the &lt;a href=&quot;https://img.ly/docs/cesdk/vue/create-video/overview-b06512/&quot;&gt;create and edit videos guide&lt;/a&gt; and the &lt;a href=&quot;https://img.ly/docs/cesdk/vue/create-video/timeline-editor-912252/&quot;&gt;timeline editor docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;customizing-the-editor&quot;&gt;Customizing the editor&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Component order.&lt;/strong&gt; Add, remove, and reorder UI elements with &lt;code&gt;setComponentOrder({ in: location }, order)&lt;/code&gt; across locations like &lt;code&gt;&apos;ly.img.dock&apos;&lt;/code&gt;, &lt;code&gt;&apos;ly.img.canvas.menu&apos;&lt;/code&gt;, and &lt;code&gt;&apos;ly.img.inspector.bar&apos;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Theming.&lt;/strong&gt; &lt;code&gt;cesdk.ui.setTheme()&lt;/code&gt; for light, dark, or system, or build one with the &lt;a href=&quot;https://img.ly/docs/cesdk/vue/user-interface/appearance/theming-4b0938/&quot;&gt;theme generator&lt;/a&gt;. See the &lt;a href=&quot;https://img.ly/demos/theming/web/&quot;&gt;theming demo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Asset libraries.&lt;/strong&gt; Serve media from your own backend or connect third-party sources. Users can browse and search both from inside the editor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feature API.&lt;/strong&gt; Show and hide functionality by context, which is how you reflect backend permissions in the UI.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Localization.&lt;/strong&gt; Override and extend every string with &lt;a href=&quot;https://img.ly/docs/cesdk/vue/user-interface/localization-508e20/&quot;&gt;full i18n support&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Reusable customizations belong in a &lt;a href=&quot;https://img.ly/docs/cesdk/vue/user-interface/ui-extensions-d194d1/&quot;&gt;plugin&lt;/a&gt;. Background removal and vectorization ship that way.&lt;/p&gt;
&lt;h2 id=&quot;where-a-vue-video-editor-pays-off&quot;&gt;Where a Vue video editor pays off&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Marketing automation.&lt;/strong&gt; Generate campaign variants from one template with &lt;a href=&quot;https://img.ly/docs/cesdk/vue/create-templates/add-dynamic-content/text-variables-7ecb50/&quot;&gt;text variables&lt;/a&gt;, and push template edits across every asset built on it. Bulk import of PSD files turns existing design work into editable scenes. This is mostly an engine job rather than a UI one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;E-learning.&lt;/strong&gt; Instructors record, trim, and caption in the browser and build a template library instead of one-off files. &lt;a href=&quot;https://img.ly/docs/cesdk/vue/user-interface/ui-extensions-d194d1/&quot;&gt;Plugins&lt;/a&gt; can add quizzes and polls.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sales outreach.&lt;/strong&gt; Personalized video at volume, with &lt;a href=&quot;https://img.ly/demos/language/web/&quot;&gt;localization&lt;/a&gt; for teams selling into several markets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Social publishing.&lt;/strong&gt; Templates, an audio library, and &lt;a href=&quot;https://img.ly/docs/cesdk/vue/animation/overview-6a2ef2/&quot;&gt;configurable animations&lt;/a&gt;, then export per platform aspect ratio.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Digital asset management.&lt;/strong&gt; Teams adapt approved footage centrally. CE.SDK has no built-in role model, so permissions live in your backend and surface through the Feature API.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;Start from the &lt;a href=&quot;https://img.ly/docs/cesdk/vue/starterkits/video-editor-e1nlor/&quot;&gt;Vue video editor starter kit&lt;/a&gt;, which is a working project rather than a snippet, or try the &lt;a href=&quot;https://img.ly/demos/video-ui/web/&quot;&gt;demo&lt;/a&gt; first.&lt;/p&gt;
&lt;p&gt;On a different framework? We have the same guide for &lt;a href=&quot;https://img.ly/blog/a-modern-react-video-editor/&quot;&gt;React&lt;/a&gt; and &lt;a href=&quot;https://img.ly/blog/a-modern-angular-video-editor/&quot;&gt;Angular&lt;/a&gt;, plus a broader &lt;a href=&quot;https://img.ly/blog/javascript-video-editing-guide/&quot;&gt;JavaScript video editing guide&lt;/a&gt; on the underlying browser tech. Still comparing vendors? See our breakdown of the &lt;a href=&quot;https://img.ly/blog/top-7-video-editing-sdks-in-2025/&quot;&gt;leading video editing SDKs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Questions about your use case? &lt;a href=&quot;https://img.ly/forms/contact-sales/&quot;&gt;Talk to us&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2025/01/video-editor-vue_js.jpg" medium="image"/><category>Vue.js</category><category>Video Editor</category><category>Video Editing</category><category>How-To</category></item><item><title>A Modern React Video Editor: Integration Guide</title><link>https://img.ly/blog/a-modern-react-video-editor/</link><guid isPermaLink="true">https://img.ly/blog/a-modern-react-video-editor/</guid><description>Learn how to integrate IMG.LY&apos;s video editor for React into your web app, from the first component to timeline edits and MP4 export.</description><pubDate>Wed, 08 Jan 2025 09:31:11 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Learn how to integrate&lt;/em&gt; &lt;a href=&quot;https://img.ly/docs/cesdk/react/starterkits/video-editor-e1nlor/&quot;&gt;&lt;em&gt;IMG.LY’s video editor for React&lt;/em&gt;&lt;/a&gt; &lt;em&gt;into your web app and make the most of all its features.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Short-form video changed what users expect from software. People who edit clips daily in TikTok or CapCut arrive at your product assuming they can trim, caption, and rearrange without leaving it. Sending them to a desktop tool and asking them to come back with an MP4 is where the workflow breaks.&lt;/p&gt;
&lt;p&gt;This guide covers integrating a video editor into a React app with CreativeEditor SDK (CE.SDK): the component setup, the timeline and export APIs underneath it, and the customization points you will reach for once the default editor is running.&lt;/p&gt;
&lt;p&gt;For a working reference, see the &lt;a href=&quot;https://img.ly/docs/cesdk/react/starterkits/video-editor-e1nlor/&quot;&gt;React video editor starter kit&lt;/a&gt; or try the &lt;a href=&quot;https://img.ly/demos/video-ui/web/&quot;&gt;interactive demo&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;check-browser-support-before-you-scope-the-work&quot;&gt;Check browser support before you scope the work&lt;/h2&gt;
&lt;p&gt;CE.SDK’s video mode encodes and decodes in the browser using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebCodecs_API&quot;&gt;WebCodecs API&lt;/a&gt;. That is what lets you export an MP4 with no render farm behind it, and it is also the catch. Video mode needs a recent Chromium browser: Chrome, Edge, Opera, Arc, and Brave all work. Safari and Firefox do not currently support video editing.&lt;/p&gt;
&lt;p&gt;Design and photo editing have no such restriction, so this only limits the video path. If your traffic skews heavily to Safari, plan for a fallback message rather than discovering it in QA. The &lt;a href=&quot;https://img.ly/docs/cesdk/react/create-video/overview-b06512/&quot;&gt;supported browsers list&lt;/a&gt; has the current detail.&lt;/p&gt;
&lt;h2 id=&quot;why-a-video-editor-belongs-in-the-app-rather-than-beside-it&quot;&gt;Why a video editor belongs in the app rather than beside it&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://newsroom.tiktok.com/en-us/1-billion-people-on-tiktok&quot;&gt;TikTok reports over a billion monthly active users&lt;/a&gt;, and &lt;a href=&quot;https://abc.xyz/2024-q1-earnings-call/&quot;&gt;Google’s earnings calls&lt;/a&gt; have put YouTube Shorts around 70 billion daily views. Those products taught a very large number of people that trimming a clip and adding a caption takes seconds.&lt;/p&gt;
&lt;p&gt;That expectation is why the round trip hurts. Every export-and-reupload cycle gives the user a chance to abandon the task, and every asset that leaves your system is one you can no longer template, version, or keep on brand. Editing in place keeps both the user and the asset.&lt;/p&gt;
&lt;p&gt;React’s component model fits this well, because the editor is one mounted component with a configuration object and an initialization hook, not a page you navigate away to.&lt;/p&gt;
&lt;h2 id=&quot;getting-started-adding-a-video-editor-in-react&quot;&gt;Getting started: adding a video editor in React&lt;/h2&gt;
&lt;h3 id=&quot;requirements&quot;&gt;Requirements&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Node.js 20+ and npm 10+. &lt;a href=&quot;https://nodejs.org/download&quot;&gt;Download Node.js&lt;/a&gt; if needed.&lt;/li&gt;
&lt;li&gt;A React 18+ project on a build tool such as Vite, Parcel, or RSBuild.&lt;/li&gt;
&lt;li&gt;A CE.SDK license key. &lt;a href=&quot;https://img.ly/docs/cesdk/&quot;&gt;Start a free trial&lt;/a&gt; to get one.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you do not have a project yet, create one with &lt;a href=&quot;https://vite.dev/guide/&quot;&gt;Vite&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; vite@latest&lt;/span&gt;&lt;span&gt; my-react-video-editor&lt;/span&gt;&lt;span&gt; --&lt;/span&gt;&lt;span&gt; --template&lt;/span&gt;&lt;span&gt; react&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; my-react-video-editor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-1-install-cesdk&quot;&gt;Step 1: Install CE.SDK&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; @cesdk/cesdk-js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-2-create-the-editor-component&quot;&gt;Step 2: Create the editor component&lt;/h3&gt;
&lt;p&gt;CE.SDK ships a React component, so you do not need to manage the instance lifecycle by hand. Import it from the &lt;code&gt;/react&lt;/code&gt; entry point and pass it a &lt;code&gt;config&lt;/code&gt; object and an &lt;code&gt;init&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Create &lt;code&gt;src/VideoEditor.jsx&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// src/VideoEditor.jsx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; CreativeEditor &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@cesdk/cesdk-js/react&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  license: &lt;/span&gt;&lt;span&gt;&apos;YOUR_LICENSE_KEY&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// replace with your key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  userId: &lt;/span&gt;&lt;span&gt;&apos;YOUR_USER_ID&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// optional, for MAU tracking across devices&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// Runs once, after the SDK instance is created&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; async&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;cesdk&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  await&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;all&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    cesdk.&lt;/span&gt;&lt;span&gt;addDefaultAssetSources&lt;/span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    cesdk.&lt;/span&gt;&lt;span&gt;addDemoAssetSources&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      sceneMode: &lt;/span&gt;&lt;span&gt;&apos;Video&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      withUploadAssetSources: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // Open the editor in video mode with an empty composition&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  await&lt;/span&gt;&lt;span&gt; cesdk.&lt;/span&gt;&lt;span&gt;createVideoScene&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; VideoEditor&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;CreativeEditor&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{config} &lt;/span&gt;&lt;span&gt;init&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{init} &lt;/span&gt;&lt;span&gt;width&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;100vw&quot;&lt;/span&gt;&lt;span&gt; height&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;100vh&quot;&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sceneMode: &apos;Video&apos;&lt;/code&gt; on &lt;code&gt;addDemoAssetSources&lt;/code&gt; loads the video and audio demo libraries rather than the design ones, so the asset panel contains clips and music instead of shapes. In production you will swap these for your own asset sources, which can be your backend or a third-party library such as &lt;a href=&quot;https://img.ly/docs/cesdk/react/import-media/from-remote-source/unsplash-8f31f0/&quot;&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;createVideoScene()&lt;/code&gt; is what puts the editor into video mode and gives you the timeline. Calling &lt;code&gt;createDesignScene()&lt;/code&gt; instead gives you the design editor with no time dimension, which is the most common reason a first integration comes up without a timeline.&lt;/p&gt;
&lt;h3 id=&quot;step-3-mount-it&quot;&gt;Step 3: Mount it&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// src/App.jsx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; VideoEditor &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./VideoEditor&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; App&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;VideoEditor&lt;/span&gt;&lt;span&gt; /&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run &lt;code&gt;npm run dev&lt;/code&gt; and open &lt;code&gt;http://localhost:5173&lt;/code&gt;. You should get a full editor with a timeline: trimming, splitting, text overlays, audio tracks, filters, and transitions.&lt;/p&gt;
&lt;p&gt;Name your own component something other than &lt;code&gt;CreativeEditor&lt;/code&gt; or &lt;code&gt;CreativeEditorSDK&lt;/code&gt;. Reusing either name collides with the import and produces an &lt;code&gt;Identifier has already been declared&lt;/code&gt; error.&lt;/p&gt;
&lt;h2 id=&quot;four-things-that-will-cost-you-an-afternoon&quot;&gt;Four things that will cost you an afternoon&lt;/h2&gt;
&lt;p&gt;These are the failure modes that come up most often in React integrations. None of them produce a useful error message, which is what makes them expensive.&lt;/p&gt;
&lt;h3 id=&quot;init-swallows-its-own-errors&quot;&gt;&lt;code&gt;init&lt;/code&gt; swallows its own errors&lt;/h3&gt;
&lt;p&gt;If any line inside the &lt;code&gt;init&lt;/code&gt; callback throws, the remaining lines are skipped and nothing appears in the console. You get an editor that loads with a half-built scene and no explanation.&lt;/p&gt;
&lt;p&gt;Wrap the body while you are developing:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; async&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;cesdk&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  try&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    await&lt;/span&gt;&lt;span&gt; cesdk.&lt;/span&gt;&lt;span&gt;addDefaultAssetSources&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    await&lt;/span&gt;&lt;span&gt; cesdk.&lt;/span&gt;&lt;span&gt;createVideoScene&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // scene setup...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  } &lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt; (error) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;[CE.SDK init] failed:&apos;&lt;/span&gt;&lt;span&gt;, error);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Symptoms to recognize: the editor renders, some blocks are missing, the console is clean, and the behavior changes depending on network timing.&lt;/p&gt;
&lt;h3 id=&quot;strict-mode-runs-init-twice&quot;&gt;Strict Mode runs &lt;code&gt;init&lt;/code&gt; twice&lt;/h3&gt;
&lt;p&gt;In development, React 18+ Strict Mode mounts, unmounts, and remounts the component. &lt;code&gt;init&lt;/code&gt; runs twice, and the first engine is disposed partway through. The editor you end up looking at is the second one.&lt;/p&gt;
&lt;p&gt;This confuses debugging because logs from both runs interleave, and errors from the first run’s async continuation are noise. If you are chasing an initialization bug, tag your logs:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; runCount &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; async&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;cesdk&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; run&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; ++&lt;/span&gt;&lt;span&gt;runCount;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`[init ${&lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt;}] start`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  await&lt;/span&gt;&lt;span&gt; cesdk.&lt;/span&gt;&lt;span&gt;createVideoScene&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`[init ${&lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt;}] scene ready`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Production builds run &lt;code&gt;init&lt;/code&gt; once. There is nothing to fix here, only something to know.&lt;/p&gt;
&lt;h3 id=&quot;relative-asset-urls-resolve-against-the-cdn&quot;&gt;Relative asset URLs resolve against the CDN&lt;/h3&gt;
&lt;p&gt;CE.SDK resolves relative URIs against &lt;code&gt;config.baseURL&lt;/code&gt;, which points at the IMG.LY CDN. A path like &lt;code&gt;/videos/intro.mp4&lt;/code&gt; will not hit your own origin. Make local asset paths absolute before handing them to the engine:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; resolveUri&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;uri&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  uri.&lt;/span&gt;&lt;span&gt;startsWith&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;/&apos;&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; `${&lt;/span&gt;&lt;span&gt;window&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;location&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;origin&lt;/span&gt;&lt;span&gt;}${&lt;/span&gt;&lt;span&gt;uri&lt;/span&gt;&lt;span&gt;}`&lt;/span&gt;&lt;span&gt; :&lt;/span&gt;&lt;span&gt; uri;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;trim-calls-do-nothing-on-unloaded-media&quot;&gt;Trim calls do nothing on unloaded media&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;setTrimOffset&lt;/code&gt; and &lt;code&gt;setTrimLength&lt;/code&gt; need the clip’s duration metadata. Call them before the resource has loaded and they fail quietly. Always &lt;code&gt;await engine.block.forceLoadAVResource(fill)&lt;/code&gt; first.&lt;/p&gt;
&lt;p&gt;One more, if you are on Next.js: the editor is browser-only and will break server-side rendering. Load it with &lt;code&gt;next/dynamic&lt;/code&gt; and &lt;code&gt;ssr: false&lt;/code&gt;, or keep it behind a client component boundary.&lt;/p&gt;
&lt;h2 id=&quot;let-an-agent-do-the-integration&quot;&gt;Let an agent do the integration&lt;/h2&gt;
&lt;p&gt;If you work in an AI-assisted editor, you can skip most of the above. IMG.LY publishes &lt;a href=&quot;https://img.ly/docs/cesdk/react/get-started/agent-skills-f7g8h9/&quot;&gt;Agent Skills for CE.SDK&lt;/a&gt;, which load CE.SDK’s documentation and conventions directly into Claude Code, Cursor, and other agent tools. The agent then writes the integration against the current API instead of whatever it remembers from training.&lt;/p&gt;
&lt;p&gt;There is also an &lt;a href=&quot;https://img.ly/docs/cesdk/react/get-started/mcp-server-fde71c/&quot;&gt;MCP server&lt;/a&gt; that exposes the docs for live lookup during a session.&lt;/p&gt;
&lt;p&gt;In practice this matters most for the parts that change between versions, such as component names and configuration shapes. We wrote about the reasoning behind it in &lt;a href=&quot;https://img.ly/blog/img-ly-agent-skills-web/&quot;&gt;Introducing IMG.LY Agent Skills&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;working-with-the-timeline-in-code&quot;&gt;Working with the timeline in code&lt;/h2&gt;
&lt;p&gt;The default UI covers most user-facing editing. When you need to build compositions programmatically, for templates, automation, or a custom UI, you work with the engine directly through &lt;code&gt;cesdk.engine&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;create-a-video-scene-and-a-page&quot;&gt;Create a video scene and a page&lt;/h3&gt;
&lt;p&gt;A page in video mode owns a timeline. Its duration is the duration of the exported video.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; engine&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; cesdk.engine;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; scene&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.scene.&lt;/span&gt;&lt;span&gt;createVideo&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; page&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;page&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(scene, page);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setWidth&lt;/span&gt;&lt;span&gt;(page, &lt;/span&gt;&lt;span&gt;1280&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setHeight&lt;/span&gt;&lt;span&gt;(page, &lt;/span&gt;&lt;span&gt;720&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setDuration&lt;/span&gt;&lt;span&gt;(page, &lt;/span&gt;&lt;span&gt;20&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// seconds&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;add-video-clips&quot;&gt;Add video clips&lt;/h3&gt;
&lt;p&gt;Video is not its own block type. You create a &lt;code&gt;graphic&lt;/code&gt; block and give it a video fill, which means the same positioning, cropping, and animation APIs apply to video as to any other element.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; video1&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;graphic&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setShape&lt;/span&gt;&lt;span&gt;(video1, engine.block.&lt;/span&gt;&lt;span&gt;createShape&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;rect&apos;&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; fill1&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;createFill&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;video&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  fill1,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;fill/video/fileURI&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;https://cdn.img.ly/assets/demo/v3/ly.img.video/videos/pexels-drone-footage-of-a-surfer-barrelling-a-wave-12715991.mp4&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setFill&lt;/span&gt;&lt;span&gt;(video1, fill1);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;sequence-clips-with-a-track&quot;&gt;Sequence clips with a track&lt;/h3&gt;
&lt;p&gt;You could position each clip by hand with time offsets, but a &lt;code&gt;track&lt;/code&gt; does it for you. A track keeps its children playing back to back with no gaps, and recalculates the offsets whenever a duration changes.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; track&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;track&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(page, track);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(track, video1);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(track, video2);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;fillParent&lt;/span&gt;&lt;span&gt;(track); &lt;/span&gt;&lt;span&gt;// size children to the page&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// The track shifts video2 automatically&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setDuration&lt;/span&gt;&lt;span&gt;(video1, &lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do not call &lt;code&gt;setWidth&lt;/code&gt; or &lt;code&gt;setHeight&lt;/code&gt; on a track. A track derives its dimensions from its children, so size the children or use &lt;code&gt;fillParent&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;trim-clips&quot;&gt;Trim clips&lt;/h3&gt;
&lt;p&gt;Blocks default to 5 seconds. If a clip is longer than its block it gets cut off; if shorter, it loops. To control which portion plays, set a trim offset and length on the fill, after the resource has loaded.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;forceLoadAVResource&lt;/span&gt;&lt;span&gt;(fill1);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setTrimOffset&lt;/span&gt;&lt;span&gt;(fill1, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// skip the first second&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setTrimLength&lt;/span&gt;&lt;span&gt;(fill1, &lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// play 10 seconds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setLooping&lt;/span&gt;&lt;span&gt;(fill1, &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;forceLoadAVResource&lt;/code&gt; call is required. Trim APIs need the duration metadata, and calling them on an unloaded resource is a common source of silent no-ops.&lt;/p&gt;
&lt;h3 id=&quot;add-audio&quot;&gt;Add audio&lt;/h3&gt;
&lt;p&gt;A video fill plays its own audio track by default, which you can mute. Separate audio blocks handle music and voiceover.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setMuted&lt;/span&gt;&lt;span&gt;(fill1, &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; audio&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;audio&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(page, audio);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  audio,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;audio/fileURI&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;https://cdn.img.ly/assets/demo/v3/ly.img.audio/audios/far_from_home.m4a&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setVolume&lt;/span&gt;&lt;span&gt;(audio, &lt;/span&gt;&lt;span&gt;0.7&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setTimeOffset&lt;/span&gt;&lt;span&gt;(audio, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// start 2s in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setDuration&lt;/span&gt;&lt;span&gt;(audio, &lt;/span&gt;&lt;span&gt;7&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;export-to-mp4&quot;&gt;Export to MP4&lt;/h3&gt;
&lt;p&gt;Export runs in a background worker, so the editor stays interactive while it encodes. The scene state is frozen when the export starts, so later edits will not appear in the file.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; page&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.scene.&lt;/span&gt;&lt;span&gt;getCurrentPage&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; blob&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;exportVideo&lt;/span&gt;&lt;span&gt;(page, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  mimeType: &lt;/span&gt;&lt;span&gt;&apos;video/mp4&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  onProgress&lt;/span&gt;&lt;span&gt;: (&lt;/span&gt;&lt;span&gt;rendered&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;encoded&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;total&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    setProgress&lt;/span&gt;&lt;span&gt;(Math.&lt;/span&gt;&lt;span&gt;round&lt;/span&gt;&lt;span&gt;((encoded &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; total) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; url&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; URL&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;createObjectURL&lt;/span&gt;&lt;span&gt;(blob);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; anchor&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;a&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;anchor.href &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; url;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;anchor.download &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;export.mp4&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;anchor.&lt;/span&gt;&lt;span&gt;click&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;URL&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;revokeObjectURL&lt;/span&gt;&lt;span&gt;(url);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wire &lt;code&gt;onProgress&lt;/code&gt; to React state and you get an export progress bar for free. Encoding a long composition takes time, and a silent wait is the fastest way to make users think the app has hung.&lt;/p&gt;
&lt;p&gt;You can also pull just the audio with &lt;code&gt;engine.block.exportAudio(page, { mimeType: &apos;audio/wav&apos; })&lt;/code&gt;, which is useful for transcription and caption pipelines.&lt;/p&gt;
&lt;p&gt;Two features worth knowing about once the basics work: &lt;a href=&quot;https://img.ly/docs/cesdk/react/create-video/apply-transitions-146026/&quot;&gt;transitions between clips&lt;/a&gt;, and &lt;a href=&quot;https://img.ly/docs/cesdk/react/create-video/update-caption-presets-e9c385/&quot;&gt;caption presets&lt;/a&gt; for styling subtitles consistently. Captions in particular tend to arrive as a request about a week after launch, because most social video is watched muted.&lt;/p&gt;
&lt;p&gt;For the full API surface, see the &lt;a href=&quot;https://img.ly/docs/cesdk/react/create-video/overview-b06512/&quot;&gt;create and edit videos guide&lt;/a&gt; and the &lt;a href=&quot;https://img.ly/docs/cesdk/react/create-video/timeline-editor-912252/&quot;&gt;timeline editor reference&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;customizing-the-editor&quot;&gt;Customizing the editor&lt;/h2&gt;
&lt;p&gt;CE.SDK is not a fixed editor with a theme switch. The main customization points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Component order.&lt;/strong&gt; Add, remove, and reorder UI elements with &lt;code&gt;setComponentOrder({ in: location }, order)&lt;/code&gt;, where locations include &lt;code&gt;&apos;ly.img.dock&apos;&lt;/code&gt;, &lt;code&gt;&apos;ly.img.canvas.menu&apos;&lt;/code&gt;, &lt;code&gt;&apos;ly.img.inspector.bar&apos;&lt;/code&gt;, &lt;code&gt;&apos;ly.img.navigation.bar&apos;&lt;/code&gt;, and &lt;code&gt;&apos;ly.img.canvas.bar&apos;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Theming.&lt;/strong&gt; Use &lt;code&gt;cesdk.ui.setTheme()&lt;/code&gt; for light, dark, or system, or build a custom theme with the &lt;a href=&quot;https://img.ly/docs/cesdk/react/user-interface/appearance/theming-4b0938/&quot;&gt;theme generator&lt;/a&gt;. See the &lt;a href=&quot;https://img.ly/demos/theming/web/&quot;&gt;theming demo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom components.&lt;/strong&gt; Register your own buttons, dropdowns, and inputs and place them alongside the built-ins, or replace built-ins entirely.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feature API.&lt;/strong&gt; Show and hide functionality by context, for example hiding controls for a particular block type.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Asset sources.&lt;/strong&gt; Serve video, audio, and image libraries from your own backend, or connect a third-party source such as &lt;a href=&quot;https://img.ly/demos/unsplash-image-assets/web/&quot;&gt;Unsplash&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Localization.&lt;/strong&gt; Override and extend every string in any language with &lt;a href=&quot;https://img.ly/docs/cesdk/react/user-interface/localization-508e20/&quot;&gt;full i18n support&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When a customization is worth reusing across projects, package it as a &lt;a href=&quot;https://img.ly/docs/cesdk/react/user-interface/ui-extensions-d194d1/&quot;&gt;plugin&lt;/a&gt;. Background removal and vectorization ship as plugins built on the same API you would use.&lt;/p&gt;
&lt;h2 id=&quot;where-a-react-video-editor-pays-off&quot;&gt;Where a React video editor pays off&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Social publishing.&lt;/strong&gt; Templates, an audio library, and &lt;a href=&quot;https://img.ly/docs/cesdk/react/animation/overview-6a2ef2/&quot;&gt;configurable animations&lt;/a&gt; let users produce platform-ready clips, then export at the right aspect ratio per destination.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Digital asset management.&lt;/strong&gt; Teams adapt and repurpose approved footage inside a central system. Templates with placeholders and locked layers keep output on brand. CE.SDK has no built-in role model, so you gate access in your own backend and use the Feature API to reflect it in the UI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Marketing automation.&lt;/strong&gt; Generate campaign variants from one template using &lt;a href=&quot;https://img.ly/docs/cesdk/react/create-templates/add-dynamic-content/text-variables-7ecb50/&quot;&gt;text variables&lt;/a&gt;, and push template changes across every asset that uses it. This is where the headless engine matters more than the UI, and it is worth reading about &lt;a href=&quot;https://img.ly/docs/cesdk/js/prebuilt-solutions/automated-video-generation-31187c/&quot;&gt;automated video generation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sales outreach.&lt;/strong&gt; Personalized video at volume, with &lt;a href=&quot;https://img.ly/demos/language/web/&quot;&gt;localization&lt;/a&gt; for multi-market teams.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;E-learning.&lt;/strong&gt; Instructors record, trim, and caption in the browser, building a reusable template library rather than one-off files.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;The fastest path from here is the &lt;a href=&quot;https://img.ly/docs/cesdk/react/starterkits/video-editor-e1nlor/&quot;&gt;video editor starter kit&lt;/a&gt;, which is a working project rather than a snippet. If you would rather see it running first, the &lt;a href=&quot;https://img.ly/demos/video-ui/web/&quot;&gt;demo&lt;/a&gt; is the same editor this guide produces.&lt;/p&gt;
&lt;p&gt;Building the same thing on another framework? We have equivalent guides for &lt;a href=&quot;https://img.ly/blog/a-modern-vue-js-video-editor/&quot;&gt;Vue.js&lt;/a&gt; and &lt;a href=&quot;https://img.ly/blog/a-modern-angular-video-editor/&quot;&gt;Angular&lt;/a&gt;, and a broader &lt;a href=&quot;https://img.ly/blog/javascript-video-editing-guide/&quot;&gt;JavaScript video editing guide&lt;/a&gt; covering the underlying browser technologies. If you are still comparing options rather than writing code, we put together a breakdown of the &lt;a href=&quot;https://img.ly/blog/top-7-video-editing-sdks-in-2025/&quot;&gt;leading video editing SDKs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Questions about a specific use case? &lt;a href=&quot;https://img.ly/forms/contact-sales/&quot;&gt;Talk to us&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2025/01/video-editor-react.jpg" medium="image"/><category>React</category><category>How-To</category><category>Video Editor</category><category>Video Editing</category></item><item><title>A Modern Angular Video Editor: Setup Guide</title><link>https://img.ly/blog/a-modern-angular-video-editor/</link><guid isPermaLink="true">https://img.ly/blog/a-modern-angular-video-editor/</guid><description>Learn how to integrate IMG.LY&apos;s video editor for Angular into your web app, from the component scaffold to timeline edits and MP4 export.</description><pubDate>Wed, 08 Jan 2025 08:19:25 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Learn how to integrate&lt;/em&gt; &lt;a href=&quot;https://img.ly/docs/cesdk/angular/starterkits/video-editor-e1nlor/&quot;&gt;&lt;em&gt;IMG.LY’s video editor&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for Angular into your web application.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;People who trim and caption clips daily in TikTok or CapCut expect the same inside your product. When they cannot, they export, edit elsewhere, and upload again. Each round trip is a chance to abandon the task, and every asset that leaves your system stops being one you can template or keep on brand.&lt;/p&gt;
&lt;p&gt;This guide covers adding a video editor to an Angular app with CreativeEditor SDK (CE.SDK): the component wiring, the timeline and export APIs underneath, and the customization points you will reach for once it runs.&lt;/p&gt;
&lt;h2 id=&quot;check-browser-support-before-you-scope-the-work&quot;&gt;Check browser support before you scope the work&lt;/h2&gt;
&lt;p&gt;CE.SDK’s video mode encodes and decodes in the browser through the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebCodecs_API&quot;&gt;WebCodecs API&lt;/a&gt;. That is what makes client-side MP4 export possible without a render backend, and it is also the constraint. Video mode requires a recent Chromium browser: Chrome, Edge, Opera, Arc, and Brave all work. Safari and Firefox do not currently support video editing.&lt;/p&gt;
&lt;p&gt;Design and photo editing have no such limit. If a meaningful share of your users are on Safari, plan a fallback now rather than in QA.&lt;/p&gt;
&lt;h2 id=&quot;how-to-set-up-a-video-editor-in-angular&quot;&gt;How to set up a video editor in Angular&lt;/h2&gt;
&lt;p&gt;Unlike React and Vue, Angular has no first-class CE.SDK component. You create the editor yourself in &lt;code&gt;ngAfterViewInit&lt;/code&gt; and dispose of it in &lt;code&gt;ngOnDestroy&lt;/code&gt;. That is a few more lines, but it is explicit and it gives you a clear place to hold the instance.&lt;/p&gt;
&lt;h3 id=&quot;requirements&quot;&gt;Requirements&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Node.js 20+ and npm 10+. &lt;a href=&quot;https://nodejs.org/download&quot;&gt;Download Node.js&lt;/a&gt; if needed.&lt;/li&gt;
&lt;li&gt;An Angular project. Create one with &lt;code&gt;ng new my-angular-video-editor&lt;/code&gt; if you do not have one.&lt;/li&gt;
&lt;li&gt;A CE.SDK license key. &lt;a href=&quot;https://img.ly/docs/cesdk/&quot;&gt;Start a free trial&lt;/a&gt; to get one.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;step-1-install-cesdk&quot;&gt;Step 1: Install CE.SDK&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; @cesdk/cesdk-js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-2-generate-the-component&quot;&gt;Step 2: Generate the component&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ng&lt;/span&gt;&lt;span&gt; generate&lt;/span&gt;&lt;span&gt; component&lt;/span&gt;&lt;span&gt; video-editor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-3-wire-up-the-editor&quot;&gt;Step 3: Wire up the editor&lt;/h3&gt;
&lt;p&gt;Open &lt;code&gt;src/app/video-editor/video-editor.component.ts&lt;/code&gt;. The editor mounts into a &lt;code&gt;&amp;#x3C;div&gt;&lt;/code&gt; you reference with &lt;code&gt;@ViewChild&lt;/code&gt;, created after the view initializes and disposed when the component goes away.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// src/app/video-editor/video-editor.component.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  AfterViewInit,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Component,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ElementRef,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  OnDestroy,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ViewChild,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@angular/core&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; CreativeEditorSDK, { Configuration } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@cesdk/cesdk-js&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Component&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  selector: &lt;/span&gt;&lt;span&gt;&apos;app-video-editor&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  standalone: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  templateUrl: &lt;/span&gt;&lt;span&gt;&apos;./video-editor.component.html&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  styleUrl: &lt;/span&gt;&lt;span&gt;&apos;./video-editor.component.css&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; VideoEditorComponent&lt;/span&gt;&lt;span&gt; implements&lt;/span&gt;&lt;span&gt; AfterViewInit&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;OnDestroy&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  @&lt;/span&gt;&lt;span&gt;ViewChild&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;cesdk_container&apos;&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;containerRef&lt;/span&gt;&lt;span&gt;!:&lt;/span&gt;&lt;span&gt; ElementRef&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  private&lt;/span&gt;&lt;span&gt; cesdk&lt;/span&gt;&lt;span&gt;?:&lt;/span&gt;&lt;span&gt; CreativeEditorSDK&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  async&lt;/span&gt;&lt;span&gt; ngAfterViewInit&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Configuration&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      license: &lt;/span&gt;&lt;span&gt;&apos;YOUR_LICENSE_KEY&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// replace with your key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      userId: &lt;/span&gt;&lt;span&gt;&apos;YOUR_USER_ID&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// optional, for MAU tracking&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      baseURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/${&lt;/span&gt;&lt;span&gt;CreativeEditorSDK&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;version&lt;/span&gt;&lt;span&gt;}/assets`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      callbacks: { onUpload: &lt;/span&gt;&lt;span&gt;&apos;local&apos;&lt;/span&gt;&lt;span&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; instance&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; CreativeEditorSDK.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      this&lt;/span&gt;&lt;span&gt;.containerRef.nativeElement,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    this&lt;/span&gt;&lt;span&gt;.cesdk &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; instance;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    await&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;all&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      instance.&lt;/span&gt;&lt;span&gt;addDefaultAssetSources&lt;/span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      instance.&lt;/span&gt;&lt;span&gt;addDemoAssetSources&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        sceneMode: &lt;/span&gt;&lt;span&gt;&apos;Video&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        withUploadAssetSources: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    await&lt;/span&gt;&lt;span&gt; instance.&lt;/span&gt;&lt;span&gt;createVideoScene&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ngOnDestroy&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    this&lt;/span&gt;&lt;span&gt;.cesdk?.&lt;/span&gt;&lt;span&gt;dispose&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    this&lt;/span&gt;&lt;span&gt;.cesdk &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; undefined&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three details are easy to get wrong here.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;createVideoScene()&lt;/code&gt; is what produces the timeline. &lt;code&gt;createDesignScene()&lt;/code&gt; gives you the design editor with no time dimension, which is the most common reason a video integration comes up without a timeline.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ngOnDestroy&lt;/code&gt; matters more in Angular than the equivalent does elsewhere. The engine holds WebAssembly memory and worker threads, and navigating away without calling &lt;code&gt;dispose()&lt;/code&gt; leaks both. Route between two views a few times without it and you will watch memory climb.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;baseURL&lt;/code&gt; line pins asset loading to the CDN build matching your installed version, which avoids version skew between the JavaScript and the assets it fetches.&lt;/p&gt;
&lt;p&gt;Then define the template at &lt;code&gt;video-editor.component.html&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; #cesdk_container&lt;/span&gt;&lt;span&gt; [style.height.vh]&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;100&quot;&lt;/span&gt;&lt;span&gt; [style.width.vw]&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;100&quot;&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-4-use-the-component&quot;&gt;Step 4: Use the component&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// src/app/app.component.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { Component } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@angular/core&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { VideoEditorComponent } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./video-editor/video-editor.component&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Component&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  selector: &lt;/span&gt;&lt;span&gt;&apos;app-root&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  standalone: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  imports: [VideoEditorComponent],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  templateUrl: &lt;/span&gt;&lt;span&gt;&apos;./app.component.html&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  styleUrl: &lt;/span&gt;&lt;span&gt;&apos;./app.component.css&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; AppComponent&lt;/span&gt;&lt;span&gt; {}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And in &lt;code&gt;app.component.html&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;app-video-editor&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;app-video-editor&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run &lt;code&gt;ng serve&lt;/code&gt;. You should get a full editor with a timeline: trimming, splitting, text overlays, audio tracks, and filters. Compare against the &lt;a href=&quot;https://img.ly/demos/video-ui/web/&quot;&gt;interactive demo&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;two-more-things-that-bite&quot;&gt;Two more things that bite&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Relative asset URLs resolve against the CDN.&lt;/strong&gt; Because &lt;code&gt;baseURL&lt;/code&gt; points at IMG.LY’s CDN, a relative URI like &lt;code&gt;/videos/intro.mp4&lt;/code&gt; resolves there rather than against your own origin. Make local asset paths absolute before handing them to the engine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Angular Universal needs a guard.&lt;/strong&gt; The editor is browser-only. If you server-side render, keep the component behind an &lt;code&gt;isPlatformBrowser&lt;/code&gt; check or it will fail during SSR.&lt;/p&gt;
&lt;h2 id=&quot;let-an-agent-do-the-integration&quot;&gt;Let an agent do the integration&lt;/h2&gt;
&lt;p&gt;If you work in an AI-assisted editor, &lt;a href=&quot;https://img.ly/docs/cesdk/angular/get-started/agent-skills-f7g8h9/&quot;&gt;Agent Skills for CE.SDK&lt;/a&gt; load CE.SDK’s current documentation and conventions into Claude Code, Cursor, and similar tools, so the code you get back matches the current API instead of a remembered one. There is also an &lt;a href=&quot;https://img.ly/docs/cesdk/angular/get-started/mcp-server-fde71c/&quot;&gt;MCP server&lt;/a&gt; for live lookup during a session. Background in &lt;a href=&quot;https://img.ly/blog/img-ly-agent-skills-web/&quot;&gt;Introducing IMG.LY Agent Skills&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;building-compositions-in-code&quot;&gt;Building compositions in code&lt;/h2&gt;
&lt;p&gt;The default UI covers user-facing editing. For templates, automation, or a custom interface, go through &lt;code&gt;this.cesdk.engine&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;scene-and-page&quot;&gt;Scene and page&lt;/h3&gt;
&lt;p&gt;A page in video mode owns a timeline, and its duration is the duration of the export.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; engine&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; instance.engine;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; scene&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.scene.&lt;/span&gt;&lt;span&gt;createVideo&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; page&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;page&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(scene, page);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setWidth&lt;/span&gt;&lt;span&gt;(page, &lt;/span&gt;&lt;span&gt;1280&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setHeight&lt;/span&gt;&lt;span&gt;(page, &lt;/span&gt;&lt;span&gt;720&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setDuration&lt;/span&gt;&lt;span&gt;(page, &lt;/span&gt;&lt;span&gt;20&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// seconds&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;clips-and-tracks&quot;&gt;Clips and tracks&lt;/h3&gt;
&lt;p&gt;Video is not its own block type. A &lt;code&gt;graphic&lt;/code&gt; block with a video fill gets you the same positioning and animation APIs as any other element. A &lt;code&gt;track&lt;/code&gt; keeps children playing back to back and recalculates offsets when durations change.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; clip&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;graphic&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setShape&lt;/span&gt;&lt;span&gt;(clip, engine.block.&lt;/span&gt;&lt;span&gt;createShape&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;rect&apos;&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; fill&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;createFill&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;video&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  fill,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;fill/video/fileURI&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;https://cdn.img.ly/assets/demo/v3/ly.img.video/videos/pexels-drone-footage-of-a-surfer-barrelling-a-wave-12715991.mp4&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setFill&lt;/span&gt;&lt;span&gt;(clip, fill);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; track&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;track&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(page, track);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(track, clip);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;fillParent&lt;/span&gt;&lt;span&gt;(track);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Size the children rather than the track. A track takes its dimensions from what it holds.&lt;/p&gt;
&lt;h3 id=&quot;trim-and-audio&quot;&gt;Trim and audio&lt;/h3&gt;
&lt;p&gt;Blocks default to 5 seconds. Longer clips get cut off, shorter ones loop. Trim APIs need duration metadata, so load the resource first.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;forceLoadAVResource&lt;/span&gt;&lt;span&gt;(fill);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setTrimOffset&lt;/span&gt;&lt;span&gt;(fill, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setTrimLength&lt;/span&gt;&lt;span&gt;(fill, &lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setMuted&lt;/span&gt;&lt;span&gt;(fill, &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; audio&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;audio&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(page, audio);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  audio,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;audio/fileURI&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;https://cdn.img.ly/assets/demo/v3/ly.img.audio/audios/far_from_home.m4a&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setVolume&lt;/span&gt;&lt;span&gt;(audio, &lt;/span&gt;&lt;span&gt;0.7&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setTimeOffset&lt;/span&gt;&lt;span&gt;(audio, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Skipping &lt;code&gt;forceLoadAVResource&lt;/code&gt; is a common bug: the trim calls fail quietly and the clip plays in full.&lt;/p&gt;
&lt;h3 id=&quot;export-to-mp4&quot;&gt;Export to MP4&lt;/h3&gt;
&lt;p&gt;Encoding runs in a background worker, so the editor stays responsive. The scene freezes at the start of the export, so later edits will not appear in the output.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; page&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.scene.&lt;/span&gt;&lt;span&gt;getCurrentPage&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; blob&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;exportVideo&lt;/span&gt;&lt;span&gt;(page, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  mimeType: &lt;/span&gt;&lt;span&gt;&apos;video/mp4&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  onProgress&lt;/span&gt;&lt;span&gt;: (&lt;/span&gt;&lt;span&gt;rendered&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;encoded&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;total&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    this&lt;/span&gt;&lt;span&gt;.progress &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; Math.&lt;/span&gt;&lt;span&gt;round&lt;/span&gt;&lt;span&gt;((encoded &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; total) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; anchor&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;a&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;anchor.href &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; URL&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;createObjectURL&lt;/span&gt;&lt;span&gt;(blob);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;anchor.download &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;export.mp4&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;anchor.&lt;/span&gt;&lt;span&gt;click&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Bind &lt;code&gt;progress&lt;/code&gt; to your template and you have a progress bar. Encoding a long composition takes time, and an unexplained wait reads as a hang.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;engine.block.exportAudio(page, { mimeType: &apos;audio/wav&apos; })&lt;/code&gt; extracts just the audio, which is useful for transcription and captioning. On that note, &lt;a href=&quot;https://img.ly/docs/cesdk/angular/create-video/update-caption-presets-e9c385/&quot;&gt;caption presets&lt;/a&gt; and &lt;a href=&quot;https://img.ly/docs/cesdk/angular/create-video/apply-transitions-146026/&quot;&gt;transitions&lt;/a&gt; are both worth exploring once the basics work.&lt;/p&gt;
&lt;p&gt;Full reference: the &lt;a href=&quot;https://img.ly/docs/cesdk/angular/create-video/overview-b06512/&quot;&gt;create and edit videos guide&lt;/a&gt; and the &lt;a href=&quot;https://img.ly/docs/cesdk/angular/create-video/timeline-editor-912252/&quot;&gt;timeline editor docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;customizing-the-editor&quot;&gt;Customizing the editor&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Component order.&lt;/strong&gt; Add, remove, and reorder UI elements with &lt;code&gt;setComponentOrder({ in: location }, order)&lt;/code&gt; across locations such as &lt;code&gt;&apos;ly.img.dock&apos;&lt;/code&gt;, &lt;code&gt;&apos;ly.img.canvas.menu&apos;&lt;/code&gt;, and &lt;code&gt;&apos;ly.img.inspector.bar&apos;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Roles.&lt;/strong&gt; &lt;a href=&quot;https://img.ly/docs/cesdk/angular/configuration-2c1c3d/&quot;&gt;CE.SDK supports roles&lt;/a&gt;, which bundle global settings and scopes. Switching role applies that role’s defaults, and you can define custom roles for specific workflows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Theming.&lt;/strong&gt; &lt;code&gt;cesdk.ui.setTheme()&lt;/code&gt; for light, dark, or system, or build one with the &lt;a href=&quot;https://img.ly/docs/cesdk/angular/user-interface/appearance/theming-4b0938/&quot;&gt;theme generator&lt;/a&gt;. See the &lt;a href=&quot;https://img.ly/demos/theming/web/&quot;&gt;theming demo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Export options.&lt;/strong&gt; Control which formats users can export, plus quality and dimensions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Asset libraries.&lt;/strong&gt; Serve media from your own backend or connect a third-party source.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Localization.&lt;/strong&gt; Override and extend every string with &lt;a href=&quot;https://img.ly/docs/cesdk/angular/user-interface/localization-508e20/&quot;&gt;full i18n support&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Package reusable customizations as a &lt;a href=&quot;https://img.ly/docs/cesdk/angular/user-interface/ui-extensions-d194d1/&quot;&gt;plugin&lt;/a&gt;. Background removal and vectorization ship that way.&lt;/p&gt;
&lt;h2 id=&quot;where-an-angular-video-editor-pays-off&quot;&gt;Where an Angular video editor pays off&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Marketing outreach.&lt;/strong&gt; Personalized video at volume beats a cold email, and &lt;a href=&quot;https://img.ly/docs/cesdk/angular/create-templates/add-dynamic-content/text-variables-7ecb50/&quot;&gt;text variables&lt;/a&gt; plus &lt;a href=&quot;https://img.ly/demos/language/web/&quot;&gt;localization&lt;/a&gt; make per-recipient variants a data problem rather than an editing one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;E-learning.&lt;/strong&gt; Instructors record, trim, and caption in the browser and build a template library instead of one-off files. &lt;a href=&quot;https://img.ly/docs/cesdk/angular/user-interface/ui-extensions-d194d1/&quot;&gt;Plugins&lt;/a&gt; can add quizzes and polls.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Social publishing.&lt;/strong&gt; Templates, an audio library, and &lt;a href=&quot;https://img.ly/docs/cesdk/angular/animation/overview-6a2ef2/&quot;&gt;configurable animations&lt;/a&gt;, then export per platform aspect ratio.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;E-commerce.&lt;/strong&gt; Short product videos raise conversion, and Amazon’s own seller guidance points at meaningful lifts. Templates plus product data generate variations at catalogue scale without a designer per SKU.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Creative automation.&lt;/strong&gt; Define templates once, then feed them from your data to produce campaign variants. Combined with A/B testing, teams ship several cuts and keep the one that performs.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;Start from the &lt;a href=&quot;https://img.ly/docs/cesdk/angular/starterkits/video-editor-e1nlor/&quot;&gt;Angular video editor starter kit&lt;/a&gt;, which is a working project rather than a snippet, or try the &lt;a href=&quot;https://img.ly/demos/video-ui/web/&quot;&gt;demo&lt;/a&gt; first.&lt;/p&gt;
&lt;p&gt;Building the same thing elsewhere? We have equivalent guides for &lt;a href=&quot;https://img.ly/blog/a-modern-react-video-editor/&quot;&gt;React&lt;/a&gt; and &lt;a href=&quot;https://img.ly/blog/a-modern-vue-js-video-editor/&quot;&gt;Vue.js&lt;/a&gt;, plus a broader &lt;a href=&quot;https://img.ly/blog/javascript-video-editing-guide/&quot;&gt;JavaScript video editing guide&lt;/a&gt; on the underlying browser technology. Still comparing options? See our breakdown of the &lt;a href=&quot;https://img.ly/blog/top-7-video-editing-sdks-in-2025/&quot;&gt;leading video editing SDKs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Questions about your use case? &lt;a href=&quot;https://img.ly/forms/contact-sales/&quot;&gt;Talk to us&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2025/01/video-editor-angular.jpg" medium="image"/><category>Angular</category><category>How-To</category><category>Video Editor</category><category>Video Editing</category></item><item><title>A Modern Video Editor SDK for Your React Native App</title><link>https://img.ly/blog/a-modern-video-editor-sdk-for-your-react-native-app/</link><guid isPermaLink="true">https://img.ly/blog/a-modern-video-editor-sdk-for-your-react-native-app/</guid><description>Learn how to integrate IMG.LY&apos;s video editor for React Native into your app and how to best leverage its capabilities.</description><pubDate>Mon, 06 Jan 2025 10:40:35 GMT</pubDate><content:encoded>&lt;p&gt;Learn how to integrate &lt;a href=&quot;https://img.ly/docs/cesdk/react-native/prebuilt-solutions/video-editor-9e533a/&quot;&gt;IMG.LY’s video editor for React Native&lt;/a&gt; into your app and how to leverage its capabilities best.&lt;/p&gt;
&lt;h2 id=&quot;why-add-a-video-editor-to-your-react-native-app&quot;&gt;Why Add a Video Editor to Your React Native App?&lt;/h2&gt;
&lt;p&gt;Video content is solidifying its status as the most engaging form of digital media. Platforms like TikTok, Instagram Reels, and YouTube Shorts have made video consumption and creation an engrained habit with billions of users. You can harness this trend by adding a video editor to your app significantly enhancing user engagement and retention.&lt;/p&gt;
&lt;p&gt;React Native, with its ability to create cross-platform applications from a single codebase, is a perfect match for IMG.LY’s &lt;strong&gt;CreativeEditor SDK Video Editor&lt;/strong&gt;. It ensures seamless performance on iOS and Android, powered by the same unified graphics engine across platforms.&lt;/p&gt;
&lt;p&gt;Whether your app focuses on social media, marketing, or eCommerce, integrating a video editor empowers users with a creative tool set while elevating the overall experience.&lt;/p&gt;
&lt;h2 id=&quot;getting-started-integrating-the-video-editor-in-react-native&quot;&gt;Getting Started: Integrating the Video Editor in React Native&lt;/h2&gt;
&lt;h3 id=&quot;requirements&quot;&gt;Requirements&lt;/h3&gt;
&lt;p&gt;Before diving into the integration, ensure your environment meets these requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;React Native&lt;/strong&gt;: 0.73+&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;iOS&lt;/strong&gt;: 16+&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Swift&lt;/strong&gt;: 5.10 (Xcode 15.4)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Android&lt;/strong&gt;: 7+&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To get started, add the &lt;strong&gt;@imgly/editor-react-native&lt;/strong&gt; package to your project:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; @imgly/editor-react-native&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;setting-up-the-editor&quot;&gt;Setting Up the Editor&lt;/h3&gt;
&lt;p&gt;Once the package is installed, initialize the editor by importing the necessary modules and creating an instance of &lt;code&gt;EditorSettingsModel&lt;/code&gt;. You’ll need a license key, which you can obtain from the IMG.LY dashboard.&lt;/p&gt;
&lt;p&gt;Here’s how to set up and launch the video editor:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;tsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; IMGLYEditor, { EditorSettingsModel } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@imgly/editor-react-native&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; openVideoEditor&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; async&lt;/span&gt;&lt;span&gt; ()&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; settings&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; EditorSettingsModel&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    license: &lt;/span&gt;&lt;span&gt;&apos;YOUR_LICENSE_KEY&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; IMGLYEditor.&lt;/span&gt;&lt;span&gt;openEditor&lt;/span&gt;&lt;span&gt;(settings);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This launches the editor with the &lt;strong&gt;Video Editor&lt;/strong&gt; preset, enabling users to trim, cut, and enhance their videos with filters, text overlays, stickers, and music.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1080px) 1080px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1080&quot; height=&quot;1080&quot; src=&quot;https://img.ly/_astro/Video-UI_Z1lXuUU.webp&quot; srcset=&quot;/_astro/Video-UI_2qSkEH.webp 640w, /_astro/Video-UI_ZfvyXY.webp 750w, /_astro/Video-UI_EFnqb.webp 828w, /_astro/Video-UI_Z1lXuUU.webp 1080w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;use-cases-building-a-tiktok-like-experience&quot;&gt;Use Cases: Building a TikTok-Like Experience&lt;/h2&gt;
&lt;p&gt;Now that the video editor is integrated into your React Native app, let’s explore some key use cases and how to configure the editor to support them.&lt;/p&gt;
&lt;h3 id=&quot;short-form-video-creation&quot;&gt;Short-Form Video Creation&lt;/h3&gt;
&lt;p&gt;For apps targeting TikTok-style short-form video content, prioritize features that simplify the editing process:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Timeline Control&lt;/strong&gt;: Allow users to trim clips and sync overlays like stickers or music.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filters &amp;#x26; Effects&lt;/strong&gt;: Offer filters to let users add certain moods to their videos with themes like retro, high contrast, or pastel tones.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Text &amp;#x26; Stickers&lt;/strong&gt;: Add captions and playful stickers for videos that are often consumed on mute.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Music &amp;#x26; Audio&lt;/strong&gt;: Let users add soundtracks or sound effects, with a library of trending music for inspirational background music.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Video Templates&lt;/strong&gt;: Provide ready-made templates that users can customize for specific occasions or themes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This setup allows influencers and brands to create professional-looking videos that they can share across social media platforms with ease.&lt;/p&gt;
&lt;h3 id=&quot;influencers-and-marketing&quot;&gt;Influencers and Marketing&lt;/h3&gt;
&lt;p&gt;If your app serves influencers or businesses, the ability to create polished, on-brand videos is key. Features to consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Branded Templates&lt;/strong&gt;: Pre-designed templates aligned with specific brand aesthetics, simplifying content creation for marketing campaigns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Watermarks&lt;/strong&gt;: Add brand logos or watermarks to videos, ensuring creators and brands maintain visibility.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These features empower influencers and businesses to quickly generate content that’s ready for distribution across platforms.&lt;/p&gt;
&lt;h3 id=&quot;e-commerce-and-user-generated-content&quot;&gt;E-commerce and User-Generated Content&lt;/h3&gt;
&lt;p&gt;Video editing is a powerful tool for e-commerce apps, enabling sellers and customers to create engaging product demos, unboxing videos, reviews and tutorials. Features like trimming, filters, and music tools make it easy to produce compelling content that enhances the shopping experience.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vendors can create promotional videos for products.&lt;/li&gt;
&lt;li&gt;Customers can share authentic reviews or tutorials, increasing trust and boosting sales.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;customization-options-with-creativeeditor-sdk&quot;&gt;Customization Options with CreativeEditor SDK&lt;/h2&gt;
&lt;p&gt;The React Native plugin offers a range of customization options to adapt the editor to your app’s needs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;UI Customization&lt;/strong&gt;: Change themes, colors, and layouts to match your app’s branding.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Video Presets&lt;/strong&gt;: Configure presets for specific use cases, such as limiting video length or optimizing for a particular resolution.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom Assets&lt;/strong&gt;: Add unique filters, stickers, and fonts to create a personalized experience for your audience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Templates&lt;/strong&gt;: Use the CreativeEditor SDK Web UI to create custom templates, enabling users to start with professional-grade designs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Integrating a video editor into your React Native appwill improve your UX, and help boost engagement, retention, and potential distribution of your product, whether you’re building a social media platform, an influencer tool, or an e-commerce app.&lt;br&gt;
With CreativeEditor SDK, you can create a TikTok-like video editing experience or offer specialized tools for businesses and creators.&lt;/p&gt;
&lt;p&gt;By following the steps in this guide, you can empower your users to create professional-quality video content directly within your app. Explore the full capabilities of the SDK by visiting the &lt;a href=&quot;https://img.ly/docs/cesdk/react-native/prebuilt-solutions/video-editor-9e533a/&quot;&gt;React Native documentation&lt;/a&gt; and getting started today.&lt;/p&gt;
&lt;p&gt;Stay tuned for updates, and don’t hesitate to &lt;a href=&quot;https://img.ly/forms/contact-sales/&quot;&gt;reach out&lt;/a&gt; with any questions.&lt;/p&gt;
&lt;p&gt;Thanks for reading!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3,000+ creative professionals gain early access to new features and updates. Don’t miss out, and&lt;/strong&gt; &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i?ref=img.ly&quot;&gt;&lt;strong&gt;subscribe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to our newsletter.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Jan</dc:creator><media:content url="https://blog.img.ly/2024/12/how-to-react-native-video-editor-sdk.jpg" medium="image"/><category>React Native</category><category>How-To</category><category>Video Editor</category><category>Expo</category></item><item><title>Javascript Video Editing: Ultimate Guide for Developers and PMs</title><link>https://img.ly/blog/javascript-video-editing-guide/</link><guid isPermaLink="true">https://img.ly/blog/javascript-video-editing-guide/</guid><description>A comprehensive guide to JavaScript video editing for developers and PMs. Learn about essential features, modern web technologies, and common tools like FFmpeg.js and IMG.LY&apos;s CE.SDK to create powerful web-based video editors.</description><pubDate>Fri, 20 Dec 2024 14:06:55 GMT</pubDate><content:encoded>&lt;p&gt;When developing or integrating a JavaScript-based video editor for the web, you must consider a number of factors to ensure the solution is both efficient and robust. This post is the definitive guide for anyone embarking on such a project. It explores the key technologies involved, their strengths and weaknesses, and how different use cases influence the choice of tech stack. We’ll examine diverse use cases, from lightweight, browser-based editors for quick edits to more advanced tools requiring complex processing and rendering. We’ll then discuss how these scenarios drive the selection of features and technology.&lt;/p&gt;
&lt;p&gt;Additionally, we will show you the best open-source solutions that can accelerate development. This technical analysis will help you make an informed “build vs. buy” decision, ensuring you select the right approach for your project. Throughout this post, we will use the example of the IMG.LY’s JavaScript video editor (see &lt;a href=&quot;https://img.ly/demos/video-ui/web/&quot;&gt;here for a demo&lt;/a&gt;), showing you how these considerations shaped its architecture and feature set. You will learn practical insights into the decision-making process behind a successful web-based video editor.&lt;/p&gt;
&lt;p&gt;Modern web technologies like WebGL, WebCodecs and WebAssembly have enabled browsers to efficiently perform resource-intensive tasks such as video editing that had hitherto been the sole domain of desktop applications. As a result Javascript based video editing tools such as &lt;a href=&quot;https://www.veed.io/&quot;&gt;veed.io&lt;/a&gt; have increased in popularity and users expects ever more sophisticated video editing capabilities inside modern video based web apps.&lt;/p&gt;
&lt;h2 id=&quot;video-editing-use-cases&quot;&gt;Video Editing Use Cases&lt;/h2&gt;
&lt;p&gt;Let’s first outline use cases and requirements of video editing applications on the web. These will inform our discussion of technical features of respective solutions below and grant a conceptual framework for evaluating potential benefits and drawbacks of each solution.&lt;/p&gt;
&lt;h3 id=&quot;simple-video-editing&quot;&gt;Simple Video Editing&lt;/h3&gt;
&lt;p&gt;Let’s start with the base case, &lt;strong&gt;simple video edits&lt;/strong&gt; including trimming, cropping and resizing and simple effects such as adjusting brightness or saturation. This is usually sufficient feature set to support video editing for the following use cases:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sales Outreach Videos:&lt;/strong&gt; Sales teams often need to quickly edit customer-specific videos to personalize their outreach. This may involve trimming irrelevant portions, adding company logos, or adjusting brightness to ensure visual clarity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Messaging Applications:&lt;/strong&gt; These often require basic editing tools to allow users to crop, trim, or apply simple filters to shared videos, ensuring they’re concise and visually appealing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Screencasting:&lt;/strong&gt; Screencasting tools benefit from trimming and resizing capabilities to focus on key parts of recorded screens. Adding effects like brightness adjustment can make tutorials clearer and more professional.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CMS Systems:&lt;/strong&gt; Content management systems may offer built-in video editing to help users optimize media assets for specific platform requirements, such as resizing for web embeds or adding subtle branding.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Screen Recording Applications:&lt;/strong&gt; Screen recording applications often include simple editing options for cleaning up recorded content by trimming extraneous sections or cropping to highlight the most relevant parts.&lt;/p&gt;
&lt;h3 id=&quot;video-annotation&quot;&gt;Video Annotation&lt;/h3&gt;
&lt;p&gt;Next, users might want to add an additional layer of information to videos and overlay other assets, such as stickers, shapes, overlays, or text. Crucially these assets need to be time-based. That is, users need control over when the asset is shown so that particular video sequences can be referenced. This introduces the need for a timeline to arrange different video components relative to each other in time, as well as features like voice-over and audio track support.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;E-commerce Reviews:&lt;/strong&gt; Sellers and reviewers can annotate product demo videos with callouts, price tags, and feature highlights to make the content more engaging and informative.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Claims Management / Insurance:&lt;/strong&gt; Insurance companies can use annotation to highlight key details in submitted video claims, such as timestamps of damage or explanatory text overlaying critical sections of footage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Real Estate:&lt;/strong&gt; Realtors might annotate property walkthroughs by adding labels, dimensions, or descriptive text overlays to highlight key features of the home or property.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Educational Applications:&lt;/strong&gt; Instructors can use annotation tools to emphasize key moments in lectures or tutorials, such as overlaying text with formulas or concepts, or adding visual shapes to guide attention.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Productivity Tools:&lt;/strong&gt; Users can annotate meeting recordings with timestamps, text notes, or overlay diagrams to summarize key decisions or action points.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Healthcare and Telemedicine:&lt;/strong&gt; Medical professionals might annotate diagnostic videos or procedure recordings to explain findings or highlight areas of interest for training purposes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Customer Support &amp;#x26; Onboarding Tools:&lt;/strong&gt; Companies can add annotations to video tutorials or troubleshooting guides to direct users through specific steps or highlight important information.&lt;/p&gt;
&lt;h3 id=&quot;video-composition&quot;&gt;Video Composition&lt;/h3&gt;
&lt;p&gt;As we’re moving away from single media editing to creating video compositions of several types of media such as audio tracks, text, images, animations, and effects to create appealing visual designs, a well-designed timeline becomes even more important. Users need to manage many different video components in time, requiring user-friendly ways to browse and integrate external assets. This editor variant is most relevant for the following use cases:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Marketing Tech (Promotional Videos):&lt;/strong&gt; Marketers can create visually stunning promotional videos by combining custom animations, background music, and text overlays for branding.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Social Media (Stories and Reels):&lt;/strong&gt; Social media creators can quickly craft short, engaging videos that combine multiple assets like stickers, animations, and dynamic transitions tailored to platform-specific formats.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Event Highlight Reels:&lt;/strong&gt; Event organizers can compile videos, photos, and music into cohesive highlight reels that encapsulate the essence of the occasion.&lt;/p&gt;
&lt;h3 id=&quot;template-based-video-creation&quot;&gt;Template-based Video Creation&lt;/h3&gt;
&lt;p&gt;For many applications, users need starting points and examples for their designs. Starting from a blank canvas is rarely necessary for most use cases. Take a simple product video that includes promotional text, a brand logo, and animations. There is no need to reinvent the wheel for these types of videos. Instead, design applications should offer template libraries to accelerate user workflows.&lt;/p&gt;
&lt;p&gt;Once we introduce workflows involving several stakeholders, such as designers setting up a certain brand framework and marketers working with and adapting these preconfigured designs, templates need to be able to constrain what edit operations adaptors can perform. These requirements are particularly important for these use cases:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Digital Asset Management:&lt;/strong&gt; Organizations can manage and deploy branded video templates across teams, ensuring consistent design and messaging.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Social Media Publishing:&lt;/strong&gt; Social media managers can utilize templates for quick turnaround on platform-specific video formats, such as Instagram Stories or LinkedIn posts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Marketing Tech:&lt;/strong&gt; Marketing teams can rely on pre-designed templates to churn out campaign videos at scale while maintaining brand consistency.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Training Videos:&lt;/strong&gt; HR or L&amp;#x26;D departments can adapt existing templates to quickly produce training materials customized for different teams or scenarios.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;IMG.LY&amp;#39;s Video Editor enables template based constraints&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1380px) 1380px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1380&quot; height=&quot;789&quot; src=&quot;https://img.ly/_astro/Video-Templating_Z2kkIrS.webp&quot; srcset=&quot;/_astro/Video-Templating_Z1JYSMc.webp 640w, /_astro/Video-Templating_jgTfX.webp 750w, /_astro/Video-Templating_1F1X1m.webp 828w, /_astro/Video-Templating_Z21vhAn.webp 1080w, /_astro/Video-Templating_Z22RxuK.webp 1280w, /_astro/Video-Templating_Z2kkIrS.webp 1380w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;creative-automation-for-video&quot;&gt;Creative Automation for Video&lt;/h3&gt;
&lt;p&gt;Finally, you can leverage data and automation to generate variations of your templates at scale, significantly boosting the productivity of use cases where users need to either test a large number of designs, publish to different channels with different requirements, or adapt designs to many slightly different instances, for example, menu designs for a franchise.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Marketing Tech:&lt;/strong&gt; Marketers can generate hundreds of ad variations for A/B testing or localization by dynamically adjusting text, visuals, or calls to action.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Social Media Publishing:&lt;/strong&gt; Social media teams can automate the creation of videos tailored to platform specifications, such as aspect ratios or resolution, while retaining core branding.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;E-commerce:&lt;/strong&gt; Retailers can produce personalized product showcase videos for different customer segments, featuring tailored offers, pricing, or recommendations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hospitality Industry:&lt;/strong&gt; Hotels and restaurants can dynamically generate location-specific promotional videos showcasing seasonal offers, menus, or events.&lt;/p&gt;
&lt;h2 id=&quot;essential-video-editing-features&quot;&gt;Essential Video Editing Features&lt;/h2&gt;
&lt;p&gt;The above use cases are enabled by a set of features from simple transforms to complex compositions. Some video editors are focused more on manipulating individual video clips while others are more oriented towards video creation providing fully-fledged multi-media composition tool. This concise overview serves as a reference for evaluating video editing solutions:&lt;br&gt;
Transforms&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cut, Trim, and Split&lt;/strong&gt;: Basic editing tools for segmenting video clips.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resize and Scale&lt;/strong&gt;: Adjusts clip dimensions, ensuring proper fit or aspect ratio.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Crop and Rotate&lt;/strong&gt;: Controls framing and orientation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zooming Capabilities&lt;/strong&gt;: A UX feature enabling detailed editing and close-up views for precision.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;adjustments&quot;&gt;Adjustments&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Basic Adjustments&lt;/strong&gt;: Controls brightness, contrast, and other visual enhancements.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filters and Effects&lt;/strong&gt;: Sets the visual appearance and atmosphere of videos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audio Tracks and Mixing&lt;/strong&gt;: Supports multi-track audio adjustments and volume balancing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Text and Overlay Options&lt;/strong&gt;: Allows visual enhancements with text, captions, and emojis, providing opacity and layering options.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;composition&quot;&gt;Composition&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Multi-media Composition&lt;/strong&gt;: Overlaying images, stickers, text as well as audio tracks are essential for creating videos through composition.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-Track Editing&lt;/strong&gt;: Elements and layers need to be position relative to each other in time allowing the creation of complex composition.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Canvas-Based Editing&lt;/strong&gt;: Provides a flexible workspace for positioning and layering media elements.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timeline Management&lt;/strong&gt;: Split, join and arrange clips on a timeline. Manages the positioning of clips and timing for seamless transitions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Animations&lt;/strong&gt;: Make static elements dynamic and control their behavior in time. Can be use to create videos from scratch and enhance the storytelling workflow of existing ones.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;IMG.LY&amp;#39;s Video Editor Timeline Feature&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1376px) 1376px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1376&quot; height=&quot;960&quot; src=&quot;https://img.ly/_astro/Video-Editor-Timeline_1BcwDq.webp&quot; srcset=&quot;/_astro/Video-Editor-Timeline_rx9BU.webp 640w, /_astro/Video-Editor-Timeline_V8i7J.webp 750w, /_astro/Video-Editor-Timeline_Z1kAtyl.webp 828w, /_astro/Video-Editor-Timeline_Z1r7Sqi.webp 1080w, /_astro/Video-Editor-Timeline_11ktN6.webp 1280w, /_astro/Video-Editor-Timeline_1BcwDq.webp 1376w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-technology-landscape&quot;&gt;The Technology Landscape&lt;/h2&gt;
&lt;p&gt;Some time in the early 2000s the web started to be viewed as a platform to run applications not just a distributed database to deliver static html documents. While Javascript development was not yet at a point to serve as foundation for the kind of application development we see today, Adobe Flash filled the role of development platform. Video editing in the early days of the web was mainly provided by Flash-based tools involving simple transform operations such as trimming and basic transitions. Java applets were another way to deliver processing intensive programs via the browser while executing them outside of the browser inside the JVM. These early attempts were either too clunky, since they could not run natively in the browser or lacked the performance to be useful for high quality editing.&lt;/p&gt;
&lt;p&gt;When HTML5 arrived, reaching a W3C recommendation in 2014, it became possible to handle multimedia content natively in the browser. Coupled with significant performance advances of Javascript and the introduction of WebRTC this opened the door for video editing on the web.&lt;/p&gt;
&lt;p&gt;Some early cloud-based editors, such as WeVideo and Magisto, while more convenient and user-friendly than its predecessors still suffered from performance issues due to latency and lacked the depth of features found in desktop software.&lt;/p&gt;
&lt;p&gt;In the past few years advances such as WebAssembly and Javascript libraries built upon it e.g. ffmpeg.js have transformed browser-based video editing. User can now perform complex editing tasks like multi-track timelines, video effects and real-time in-browser rendering. Modern web-based solution have even come to rival desktop apps, because they can take advantage of GPU acceleration, modern APIs like WebGL and UI frameworks such as React.&lt;/p&gt;
&lt;p&gt;Let’s have a look at the state of the art web technologies that allow us to create performant video editing experiences inside the browsers. We are going to explore their relative strength, their complexities and conclude with when to best use each of these technologies:&lt;/p&gt;
&lt;h3 id=&quot;canvas-api&quot;&gt;Canvas API&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API&quot;&gt;HTML5 Canvas API&lt;/a&gt; should be most familiar to most modern web developers, since it’s a familiar and popular way to render 2D graphics in the browser. It’s use for video editing is limited and restricted to simple overlays, trimming, composition and animation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Complexity:&lt;/strong&gt; Canvas is the least complex of the technologies introduced below and overlaps with the WebGL feature set to some extend, it’s API is well-known to most web developers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advantages:&lt;/strong&gt; Canvas is lightweight, compatible across all browsers, and easy to implement, making it a great choice for simple use cases that require basic effects and no timeline.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Downsides:&lt;/strong&gt; While well suited for simpler tasks Canvas lacks the GPU-acceleration of WebGL, hence it is not recommended for resource intensive operation or performance sensitive use cases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When to Use:&lt;/strong&gt; Choose Canvas for simple editing tasks, like trimming or basic overlays, or if you need a fallback technology that works well on legacy browsers and devices.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;webgl&quot;&gt;WebGL&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API&quot;&gt;WebGL&lt;/a&gt; opens up the power of GPU-accelerated graphics to the browser, making it the default choice for any use case requiring high performance rendering. As such modern Javascript video editing solution are well served by webGL when looking to render visual effects in real time, add transitions or facilitate multi-layer compositions by leveraging the GPU.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Complexity:&lt;/strong&gt; WebGL comes with a steep learning curve especially if you are unfamiliar with 3D graphics processing, shaders and GPU programming.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advantages:&lt;/strong&gt; WebGL delivers high performance for processing complex video effects and can handle significant volume of data without latency. That makes it ideal for advanced, highly responsive video editing features.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Downsides:&lt;/strong&gt; It can be challenging to engineer modular and maintainable WebGL code, debugging shaders and ensuring consistent performance across devices is an art in itself. WebGL might also be overpowered for simple editing use cases that do not justify the added complexity.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When to Use:&lt;/strong&gt; Use WebGL if you’re creating a video editor with high-performance demands, particularly if real-time effects, transitions, or multi-layer compositing are needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;webcodecs-api&quot;&gt;WebCodecs API&lt;/h3&gt;
&lt;p&gt;Next up in our arsenal of formidable web technologies is a recent addition to modern browsers, WebCodecs, provide direct access to hardware accelerated video encoding and decoding.&lt;/p&gt;
&lt;p&gt;The WebCodecs API is a recent addition to the browser, allowing direct access to hardware-accelerated video decoding and encoding. This API makes it easier to handle high-resolution video without delays, thanks to efficient decoding directly in the browser.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Complexity:&lt;/strong&gt; WebCodecs is relatively easy to use for those familiar with media formats. However, you may need other technologies for rendering and complex editing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advantages:&lt;/strong&gt; This API offers quick access to hardware acceleration, ideal for managing large video files. With it, you can efficiently handle high-definition video playback and streaming.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Downsides:&lt;/strong&gt; Browser support for WebCodecs is still expanding, so compatibility might be a concern. Additionally, WebCodecs alone doesn’t provide a full editing suite; it needs to be combined with rendering and compositing technologies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When to Use:&lt;/strong&gt; WebCodecs is perfect if you need efficient decoding and encoding, especially for handling high-definition playback or live streaming.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;webassembly-wasm&quot;&gt;WebAssembly (Wasm)&lt;/h3&gt;
&lt;p&gt;The next performance frontier browser pushed towards was enabling near-native performance by compiling languages like C++ or Rust into a format that efficiently runs in Javascript. This format is &lt;a href=&quot;https://webassembly.org/&quot;&gt;WebAssembly&lt;/a&gt;, which makes it possible to handle computationally expensive tasks like encoding, decoding or frame manipulation inside the browser.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Complexity:&lt;/strong&gt; Working with WebAssembly is significantly more complex that the technologies discussed above. Developers need knoweldge of C++ or Rust as well as experience compiling to Wasm.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advantages:&lt;/strong&gt; WebAssembly enables browsers to handle complex video processing tasks, such as encoding and decoding, with near-native performance. Libraries such as FFmpeg build upon WebAssembly to make familiar video tools available to web developers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Downsides:&lt;/strong&gt; Development with Wasm is complex, and debugging can be a challenge. Additionally, Wasm modules may increase load times.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When to Use:&lt;/strong&gt; Use WebAssembly when building native libraries for complex operation and expensive computations, such as encoding and decoding.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our article o&lt;a href=&quot;https://img.ly/blog/how-to-build-a-video-editor-with-wasm-in-react/&quot;&gt;n building a video editor with React and Wasm&lt;/a&gt; gives you a real-world starting point for your own apps.&lt;/p&gt;
&lt;h3 id=&quot;mediastream-api&quot;&gt;MediaStream API&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/MediaStream&quot;&gt;MediaStream API&lt;/a&gt; is essential for gaining easy access to live video sources from within the browser, such as webcams. If your video editing app includes a feature for real-time recording or streaming the MediaStream API is an essential tool.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Complexity:&lt;/strong&gt; MediaStream exposes a fairly simple API and is relatively easy to learn for experienced web developers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advantages:&lt;/strong&gt; This API is well-suited for video feeds with low latency such as recording or streaming and does require addition encoding or decoding.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Downsides:&lt;/strong&gt; Any use case requiring post-production video has to rely on additional technologies or frameworks, as the MediaStream API is limited to live feeds. The quality of the stream depends on the input source and can vary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When to Use:&lt;/strong&gt; Use MediaStream for applications with live recording or streaming functionality.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;web-audio-api&quot;&gt;Web Audio API&lt;/h3&gt;
&lt;p&gt;The final web technology essential for video editing is the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API&quot;&gt;Web Audio API&lt;/a&gt;. Whether you want to add effects or mix multiple audio tracks, this API offers sophisticated tools for audio manipulation.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Complexity:&lt;/strong&gt; For developers unfamiliar with audio processing the learning curve can be stepp, however the API is well designed and there is a host of educational resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advantages:&lt;/strong&gt; Web Audio API allows precise control over audio enabling your app to offer audio adjustments such as effects or reverb and multi-track editing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Downsides:&lt;/strong&gt; It can be challenging to accurately synchronize audio with video, especially if your app includes a real-time component.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When to Use:&lt;/strong&gt; Opt for Web Audio API when audio editing is a core feature of your video editor.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;using-these-technologies-together&quot;&gt;Using These Technologies Together&lt;/h3&gt;
&lt;p&gt;Together, these technologies can be use to build a comprehensive browser based editor that is virtually indistinguishable from its desktop based counterparts. Different parts of the video editing workflow can be handled by each technology, while some choices have to made depending on the complexity and requirements of your projects, e.g. whether you’ll need resource intensive processing or an integration will real-time sources.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Video Decoding&lt;/strong&gt; - WebCodecs API (for efficient video loading and playback).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rendering&lt;/strong&gt; - WebGL (for high-performance effects) and Canvas API (for simpler editing features).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Complex Processing&lt;/strong&gt; - WebAssembly (for encoding/decoding and using native libraries like FFmpeg).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audio Processing&lt;/strong&gt; - Web Audio API (for mixing and adding effects to soundtracks).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Live Recording&lt;/strong&gt; - MediaStream API (to capture live video from devices).&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;open-source-javascript-video-editing-libraries&quot;&gt;Open Source Javascript Video Editing Libraries&lt;/h2&gt;
&lt;p&gt;Fortunately in many cases someone has already done the heavy lifting and abstracted those browser APIs into simple to use libraries and frameworks. We’ll explore the most prominent ones distinguishing between projects that are for processing raw video and those that already provide an API for you to use. It is important to note that the libraries introduced below do not provide a video editing UI, unfortunately there are no open source video editors offering an end user interface that meet the standards for inclusion in a production grade application. None of the projects we evaluated met the demands we place on third-party libraries with respect to robustness, stability, maintenance and future development. However many can provide good starting points and references on how to build your own UI such as &lt;a href=&quot;https://github.com/mifi/reactive-video&quot;&gt;Reactive Video&lt;/a&gt; for React UIs.&lt;/p&gt;
&lt;h3 id=&quot;ffmpegjs&quot;&gt;FFmpeg.js&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/ffmpegwasm/ffmpeg.wasm&quot;&gt;FFmpeg.js&lt;/a&gt; is the JavaScript port of the popular FFmpeg library compiled into WebAssembly. It enables developers to manipulate and process raw video files entirely in the browser. You can trim, convert formats, extract audio, and apply filters to videos without needing external software. However, FFmpeg just gives you the raw toolchain for building video editing features, you are still tasked with building the entire UX and editing workflows. We have an extensive guide on FFmpeg that you can consult to explore its capabilities and get started learning FFmpeg syntax.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Advantages:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Most comprehensive library for web based video and audio processing.&lt;/li&gt;
&lt;li&gt;Fully client-side, no need for server-side processing.&lt;/li&gt;
&lt;li&gt;Highly flexible, allowing fine-grained control over video workflows.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Downsides:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Fairly complex for beginners with a steep learning curve, requires familiarity with FFmpeg’s command-line syntax.&lt;/li&gt;
&lt;li&gt;FFmpeg is licensed under LGPL which makes it ill-suited for most commercial projects.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;**When to Use:**FFmpeg.js is best suited for projects with custom requirements and UI making it necessary to exert fine-grained control over video processing tasks, especially for use cases like format conversion, advanced editing pipelines, or serverless video workflows.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following two libraries allow you to programatically create and edit videos, we focus on the most stable, popular libraries here, while there might be promising up and comers we want to ensure a degree of dependability of the third-party code to be used in production systems.&lt;/p&gt;
&lt;h3 id=&quot;remotion&quot;&gt;Remotion&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.remotion.dev/&quot;&gt;Remotion&lt;/a&gt; is a React-based framework that enables developers to edit or create videos programmatically in a declarative fashion using React components. React’s declarative syntax makes it comparatively simple to manage video content and Remotion provides a convenient UI for previewing and editing videos. While its studio UI cannot be embedded directly, Remotion can serve as the graphics processing engine for custom UIs. Although it is a commercial project, it offers a generous free tier for individuals and small businesses.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Advantages:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Leverages React’s declarative model for seamless video creation.&lt;/li&gt;
&lt;li&gt;Provides robust video preview capabilities for iterative development.&lt;/li&gt;
&lt;li&gt;Flexible integration with custom-built UIs.&lt;/li&gt;
&lt;li&gt;Generous free tier for non-commercial and small-scale projects.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Downsides:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;The built-in studio UI cannot be embedded, requiring developers to create their own UI for embedding.&lt;/li&gt;
&lt;li&gt;React-specific, limiting use in non-React environments.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;**When to Use:**Use Remotion when building React-based video applications that require programmatic video generation or dynamic video content. It’s ideal for teams already familiar with React and for applications where embedding is not a core requirement.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;etrojs&quot;&gt;&lt;strong&gt;Etro.js&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Similarly to Remotion, Etro.js is a JavaScript framework for programmatic video editing, it is framework agnostic and provides an API for simple composition of layers, effects and exporting videos.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Advantages:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Includes support for advanced effects using GLSL shaders.&lt;/li&gt;
&lt;li&gt;Designed for in-browser video workflows.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Downsides:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Minimal community support compared to larger projects.&lt;/li&gt;
&lt;li&gt;Requires additional effort to create a full UI.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When to Use:&lt;/strong&gt; Suitable for applications where programmatic control and customization are key.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;extensibility&quot;&gt;Extensibility&lt;/h2&gt;
&lt;p&gt;An important consideration when deciding to buy a prebuilt video editing solution is the degree of customization and extensibility required by your use case versus how critical speed to market is. While most SDKs provide enough flexibility by exposing cor API to build a solution that best suits your needs, this level of technical control comes at the expense of higher development and maintenance efforts. White-label solutions on the other end of the spectrum offer limited customization often relying on iFrames for embedding while providing maximum speed to market. If you are still in the phase where you need to make the business case for video editing features these might be key to allowing to quickly iterate. To learn more about weighing the pros and cons of SDK vs. White-label explore our &lt;a href=&quot;https://img.ly/blog/sdk-vs-white-label-consider-these-differences-when-you-choose-a-solution/&quot;&gt;extensive guide on the topic&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;IMG.LY’s CE.SDK achieves extensibility by providing an &lt;a href=&quot;https://img.ly/blog/img-ly-sdk-plugin-system/&quot;&gt;interface for plugins&lt;/a&gt; that allow developers to add custom features and UI elements.&lt;/p&gt;
&lt;h2 id=&quot;cross-platform-video-editing&quot;&gt;Cross Platform Video Editing&lt;/h2&gt;
&lt;p&gt;While this post is dedicated specifically to Javascript video editing an important consideration for choosing a video editing tech stack is whether there exists an intermediary output format that preserves editing operations so that videos can be edited on other devices and platforms. This is important for collaborative video editing use cases as well as use cases where videos are captured and basic edits performed on mobile and the finishing touches performed on the desktop.&lt;br&gt;
These consideration are particular pertinent for the Real Estate, Telemedicine and Productivity use cases described above, since they involve either a multi-device or collaborative component.&lt;/p&gt;
&lt;p&gt;At most common libraries or SDKs can achieve that by offering support for some form of serialization, that is exporting the edit operations along with the unedited video to then reapply edits upon import.&lt;/p&gt;
&lt;p&gt;IMG.LY’s CE.SDK, on the other hand, is the only video editing SDK that is truly cross-platform. That means it is built atop a single creative engine that is portable to any platform. Whether iOS, Android, Desktop, or the Web, every platform uses the same underlying tech and uses the same custom format for scenes which contain all assets and edits making error-prone serializations obsolete.&lt;/p&gt;
&lt;p&gt;Furthermore:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;iOS and Android make use of the same underlying API.&lt;/li&gt;
&lt;li&gt;Cross platform feature parity is baked into the cake. Since core functionality is implemented at the engine level, features are guaranteed to be available on both platform, although the timeline might differ somewhat.&lt;/li&gt;
&lt;li&gt;Designs are 100% interoperable and consistent between platforms. Exporting and importing design files across platforms works seamlessly and final renderings are guaranteed to be consistent.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;javascript-video-editing--generative-ai&quot;&gt;Javascript Video Editing &amp;#x26; Generative AI&lt;/h2&gt;
&lt;p&gt;Generative AI affects video editing and generation across the board. Text-to-video is the obvious case, but AI is also changing how videos get composed and edited in less visible ways: automated transitions, color grading, voice enhancement, voiceover generation, background removal, and inpainting.&lt;/p&gt;
&lt;p&gt;These capabilities come from a shifting set of specialist providers, and which one is best changes on a scale of months. Two design consequences follow from that.&lt;/p&gt;
&lt;p&gt;First, a JavaScript video editor has to be open enough to act as an integrator. It needs to combine voice tracks, clips, text, and other media programmatically before a user ever sees the timeline, and it needs to let you swap the model behind any one of those steps without rebuilding the editor.&lt;/p&gt;
&lt;p&gt;Second, the human has to stay in the loop. AI output is uneven, and refining an unchangeable artifact by re-prompting is slow and imprecise. Generated material should land in the scene as editable blocks, so users can trim, replace, and regenerate individual parts rather than rolling the dice on the whole clip again.&lt;/p&gt;
&lt;p&gt;We built &lt;a href=&quot;https://img.ly/blog/build-in-a-day-ai-video-clipping-with-ce-sdk/&quot;&gt;an AI video clipping tool in a day&lt;/a&gt; on that principle, and &lt;a href=&quot;https://img.ly/blog/animate-between-images-ai-native-video-workflows-with-ce-sdk-and-veo-3/&quot;&gt;animating between images with Veo 3&lt;/a&gt; shows the generated-but-still-editable workflow end to end.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;When building or integrating a JavaScript video editor, developers and PMs have to navigate a complex technology landscape and make myriad decisions along the way. This guide has covered everything from essential use cases and feature sets to the cutting-edge technologies that underly browser-based video editing. Whether your project requires basic trimming tools or advanced multimedia composition, understanding the benefits and downsides of the various solutions like Canvas, WebGL, WebCodecs, WebAssembly, and more is crucial for choosing the right stack.&lt;/p&gt;
&lt;p&gt;We’ve also explored how open-source tools like FFmpeg.js, Remotion, and Etro.js can accelerate development, while SDKs like IMG.LY’s CE.SDK offer unmatched extensibility and cross-platform compatibility. For those navigating the impact of generative AI on video editing, the need for seamless integration and user-centric design remains important.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If you’re looking for a robust, modern video editing solution for your web application, explore our showcase and start a free trial.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For the framework-specific version of this, we have setup guides for &lt;a href=&quot;https://img.ly/blog/a-modern-react-video-editor/&quot;&gt;React&lt;/a&gt;, &lt;a href=&quot;https://img.ly/blog/a-modern-vue-js-video-editor/&quot;&gt;Vue.js&lt;/a&gt; and &lt;a href=&quot;https://img.ly/blog/a-modern-angular-video-editor/&quot;&gt;Angular&lt;/a&gt;. If you are still comparing vendors rather than writing code, start with our breakdown of the &lt;a href=&quot;https://img.ly/blog/top-7-video-editing-sdks-in-2025/&quot;&gt;leading video editing SDKs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One practical note if you build with an AI assistant. The APIs in this space move quickly, and models tend to produce integrations against whichever version was in their training data. &lt;a href=&quot;https://img.ly/docs/cesdk/js/get-started/agent-skills-f7g8h9/&quot;&gt;Agent Skills for CE.SDK&lt;/a&gt; and the &lt;a href=&quot;https://img.ly/docs/cesdk/js/get-started/mcp-server-fde71c/&quot;&gt;MCP server&lt;/a&gt; load the current documentation into Claude Code, Cursor, and similar tools so the generated code matches the API that actually ships. We wrote about why in &lt;a href=&quot;https://img.ly/blog/img-ly-agent-skills-web/&quot;&gt;Introducing IMG.LY Agent Skills&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>Jan</dc:creator><media:content url="https://blog.img.ly/2024/12/Javascript-Editor--1-.jpg" medium="image"/><category>Video Editing</category><category>Video Editor</category><category>CE.SDK</category><category>Automation</category><category>Cross-Platform</category><category>JavaScript</category></item><item><title>CE.SDK Video Editor Now Available on Android</title><link>https://img.ly/blog/ce-sdk-video-editor-now-available-on-android/</link><guid isPermaLink="true">https://img.ly/blog/ce-sdk-video-editor-now-available-on-android/</guid><description>Integrate a fully-customizable Video Editor into your Android App with CE.SDK.</description><pubDate>Tue, 22 Oct 2024 11:44:02 GMT</pubDate><content:encoded>&lt;p&gt;We are excited to announce the release of CE.SDK’s video editing and video content creation tools for Android!&lt;/p&gt;
&lt;p&gt;After the successful iOS launch, CE.SDK’s professional video editing capabilities are now available for Android. Whether your app focuses on social media, e-commerce, or marketing technology, CE.SDK enables users to create high-quality videos directly within your app.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-36/uncompressed/Android-crop-split-trim.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h2&gt;
&lt;p&gt;Getting up and running with an instance of the CE.SDK video editor for Android is easy.&lt;/p&gt;
&lt;p&gt;After downloading your license (get your trial license here) from your dashboard, simply &lt;a href=&quot;https://img.ly/docs/cesdk/android/starterkits/video-editor-e1nlor/&quot;&gt;invoke &lt;code&gt;VideoEditor&lt;/code&gt; as composable function, Activity or Fragment.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;our-video-editing-backstory&quot;&gt;Our Video Editing Backstory&lt;/h2&gt;
&lt;p&gt;Since we launched VideoEditor SDK almost ten years ago, we have seen an astounding range of creative and unique use cases of our SDK in customer projects. From Cameo connecting celebrities and their fans in new ways, over Multibrain supercharging their users marketing campaigns with editable video content, to &lt;a href=&quot;https://zigazoo.com/&quot;&gt;Zigazoo&lt;/a&gt; powering video content within their social network for kids while putting safety and parental control first.&lt;/p&gt;
&lt;p&gt;Since then, millions of users have experienced IMG.LY’s VideoEditor SDK through our customers’ products, shaping how they expect to interact with and modify videos. Continuous feedback from both our customers and their users has also influenced the way we approach video interface design, helping us refine and innovate along the way.&lt;/p&gt;
&lt;p&gt;Our goal was to combine the reliability and robustness of the VideoEditor SDK with true cross-platform compatibility and the flexibility to meet diverse needs. By applying the lessons we’ve learned, we aimed to deliver an exceptional video editing user experience straight out of the box. We described how those learnings shaped the &lt;a href=&quot;https://img.ly/blog/designing-a-timeline-for-mobile-video-editing/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=androidvideo&quot;&gt;design of the mobile video editing interface.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;key-capabilities&quot;&gt;Key Capabilities&lt;/h2&gt;
&lt;p&gt;With CE.SDK’s sleek timeline interface, your Android users can now take their video editing from simple transforms and adjustments to complex composition and multi-track editing:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Timeline-Based Editing&lt;/strong&gt;&lt;br&gt;
Split, trim, arrange video and audio tracks. Position elements such as images and stickers on the timeline and control their duration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Multi-Track Editing&lt;/strong&gt;&lt;br&gt;
Work with multiple video and audio tracks, allowing for complex composition.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transform &amp;#x26; Enhance&lt;/strong&gt;&lt;br&gt;
Crop, flip, rotate, and use presets for common video formats. Add filters, effects, blur and essential adjustments.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Customizable Templates&lt;/strong&gt;&lt;br&gt;
Create and import templates using our web video editor, to jumpstart your users’ video composition and designs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Asset Integration&lt;/strong&gt;&lt;br&gt;
Integrate your own asset libraries for audio tracks, sound effects, images, and more.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cross-platform Interoperability&lt;/strong&gt;&lt;br&gt;
CE.SDK’s video capabilities extends across iOS, Android and the Web, enabling cross-platform applications to offer seamless video editing capabilities. Users can edit and save work in progress and pick up on any device.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href=&quot;https://img.ly/demos/video-ui/android/&quot;&gt;showcase app for an interactive demo&lt;/a&gt; of these features.&lt;/p&gt;
&lt;h2 id=&quot;customization&quot;&gt;Customization&lt;/h2&gt;
&lt;p&gt;The ability to tailor the video editor to your app’s particular use case has been a front and center concern in its development.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/android/configuration-2c1c3d/&quot;&gt;&lt;strong&gt;UI Customization&lt;/strong&gt;&lt;/a&gt;: While theming is currently limited to &lt;code&gt;dark&lt;/code&gt; and &lt;code&gt;light&lt;/code&gt; model, future releases will introduce more flexible theming, allowing you to modify the look and feel of the editor to match your app’s branding. Furthermore, we expose &lt;strong&gt;callbacks&lt;/strong&gt; that make it possible to hook into editor events and &lt;strong&gt;overlays&lt;/strong&gt; for custom dialogues.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/android/create-video-c41a08/&quot;&gt;&lt;strong&gt;Configure Video Presets&lt;/strong&gt;&lt;/a&gt;: You can configure the editor to create video presets based on your users’ needs. For instance, you may want to fix the video’s aspect ratio or optimize for certain resolutions, depending on the target platform.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/android/use-templates/apply-template-35c73e/&quot;&gt;&lt;strong&gt;Video Templates&lt;/strong&gt;&lt;/a&gt;: With the CE.SDK video editor web UI, you can create an unlimited number of video templates, such as collages, text designs, and animations, providing your users with professional-quality starting points for their video designs.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/android/import-media/asset-panel/customize-c9a4de/&quot;&gt;&lt;strong&gt;Assets&lt;/strong&gt;&lt;/a&gt;: Provide custom filters, fonts, and stickers to enhance the user experience. For niche apps, this can be an excellent way to engage users by offering content that feels unique to your community.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;ideal-for-social-media-ecommerce-and-marketing-tech-apps&quot;&gt;Ideal for Social Media, Ecommerce, and Marketing Tech Apps&lt;/h2&gt;
&lt;p&gt;CE.SDK’s new Android video editing capabilities are perfect for a variety of use cases, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/use-cases/story-reels-short-video-creation/&quot;&gt;&lt;strong&gt;Social Media Applications&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; The CE.SDK video editor for Android excels at short-form video, ideal for social media applications, whether your users are publishing to other networks or you run a network yourself.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/industries/e-commerce/&quot;&gt;&lt;strong&gt;Ecommerce&lt;/strong&gt;&lt;/a&gt;: Allow your users to create engaging product showcases, ads, and promotional videos, testimonials or reviews.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/industries/marketing-tech/&quot;&gt;&lt;strong&gt;Marketing Tech Platforms&lt;/strong&gt;&lt;/a&gt;: Users can leverage our versatile templating to easily create polished social media and marketing graphics from within your app.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;whats-next&quot;&gt;What’s Next?&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Camera UI: Record videos on Android.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;988&quot; src=&quot;https://img.ly/_astro/camera-UI-Android-1_1EaiJa.webp&quot; srcset=&quot;/_astro/camera-UI-Android-1_Z1RlqqG.webp 640w, /_astro/camera-UI-Android-1_Z2cz0Wn.webp 750w, /_astro/camera-UI-Android-1_Z1p7sjP.webp 828w, /_astro/camera-UI-Android-1_Z1B2Obe.webp 1080w, /_astro/camera-UI-Android-1_Z1vhLKG.webp 1280w, /_astro/camera-UI-Android-1_1EaiJa.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;This Android release is just the beginning! We are about to launch a &lt;strong&gt;Camera UI&lt;/strong&gt; for Android and are working on more advanced template creation features. So stay tuned.&lt;br&gt;
To see some of these features in action, check out our iOS demo, where the next phase of innovation is unfolding.&lt;/p&gt;
&lt;h2 id=&quot;get-started&quot;&gt;Get Started&lt;/h2&gt;
&lt;p&gt;Explore our &lt;a href=&quot;https://img.ly/demos/video-ui/android/&quot;&gt;Video UI Showcase&lt;/a&gt; and &lt;a href=&quot;https://img.ly/docs/cesdk/android/starterkits/video-editor-e1nlor/&quot;&gt;Documentation for Android&lt;/a&gt; to discover how CE.SDK can streamline your content creation projects and make Android video editing easier than ever.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Over 3,000 creative professionals gain early access to new features and updates. Don’t miss out, and&lt;/strong&gt; &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;&lt;strong&gt;subscribe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to our newsletter.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Jan</dc:creator><media:content url="https://blog.img.ly/2024/10/android-video-editor-sdk-imgly-creative-editor_s.jpg" medium="image"/><category>Android</category><category>Android App Development</category><category>Creative Editor</category><category>Video Editing</category><category>Video Editor</category></item><item><title>A Modern Video Editor SDK for your Flutter App</title><link>https://img.ly/blog/a-modern-video-editor-sdk-for-your-flutter-app/</link><guid isPermaLink="true">https://img.ly/blog/a-modern-video-editor-sdk-for-your-flutter-app/</guid><description>Learn how to integrate IMG.LY&apos;s video editor into your Flutter app on iOS and Android, from the pubspec entry to a working editor.</description><pubDate>Fri, 13 Sep 2024 11:26:15 GMT</pubDate><content:encoded>&lt;p&gt;Mobile users who cut clips in TikTok or CapCut every day expect the same inside your app. Sending them out to another editor and back is where the workflow breaks, and where your app stops owning the content.&lt;/p&gt;
&lt;p&gt;This guide covers adding a video editor to a Flutter app with CreativeEditor SDK (CE.SDK): the setup, the presets, and what you can customize once it runs.&lt;/p&gt;
&lt;h2 id=&quot;video-editing-works-on-both-ios-and-android&quot;&gt;Video editing works on both iOS and Android&lt;/h2&gt;
&lt;p&gt;Worth stating plainly, because this post used to say otherwise. When it was first published in September 2024, CE.SDK video editing shipped on iOS only. &lt;a href=&quot;https://img.ly/blog/ce-sdk-video-editor-now-available-on-android/&quot;&gt;Android support landed the following month&lt;/a&gt;. Both platforms are supported from the same Flutter plugin today.&lt;/p&gt;
&lt;h2 id=&quot;why-add-a-video-editor-to-your-flutter-app&quot;&gt;Why add a video editor to your Flutter app&lt;/h2&gt;
&lt;p&gt;Short-form video reset what people consider normal. Trimming a clip, adding a caption, and dropping in music is something a very large number of users now do without thinking about it, and they expect to do it where they already are.&lt;/p&gt;
&lt;p&gt;For your app, the payoff is retention and ownership. Every export-and-reupload round trip is a chance to lose the user, and every video finished somewhere else is one you cannot template, moderate, or keep on brand.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot;&gt;Getting started&lt;/h2&gt;
&lt;h3 id=&quot;requirements&quot;&gt;Requirements&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Flutter 3.3.0 or later, Dart SDK 3.4.3 or later&lt;/li&gt;
&lt;li&gt;iOS and Android are both supported. Check the &lt;a href=&quot;https://img.ly/docs/cesdk/flutter/get-started/overview-e18f40/&quot;&gt;Flutter getting-started guide&lt;/a&gt; for current platform minimums.&lt;/li&gt;
&lt;li&gt;A CE.SDK license key. &lt;a href=&quot;https://img.ly/docs/cesdk/&quot;&gt;Start a free trial&lt;/a&gt; to get one.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Add the plugin to &lt;code&gt;pubspec.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dependencies&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  flutter&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    sdk&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;flutter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  imgly_editor&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;^1.80.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pin with a caret rather than an exact version so you pick up patch releases. Check &lt;a href=&quot;https://pub.dev/packages/imgly_editor&quot;&gt;pub.dev&lt;/a&gt; for the current release before you start, since the plugin tracks the CE.SDK engine and moves regularly.&lt;/p&gt;
&lt;h3 id=&quot;open-the-editor&quot;&gt;Open the editor&lt;/h3&gt;
&lt;p&gt;Import the package:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;dart&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;package:imgly_editor/imgly_editor.dart&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then open it with an &lt;code&gt;EditorSettings&lt;/code&gt; instance and the video preset. The license key is required. &lt;code&gt;userId&lt;/code&gt; is optional and only used for monthly active user counting across devices.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;dart&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; VideoEditorSolution&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Future&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;openEditor&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    final&lt;/span&gt;&lt;span&gt; settings &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; EditorSettings&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      license&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &apos;YOUR_LICENSE_KEY&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      userId&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &apos;YOUR_USER_ID&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    final&lt;/span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; IMGLYEditor&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;openEditor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      preset&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; EditorPreset&lt;/span&gt;&lt;span&gt;.video,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      settings&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; settings,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (result &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; null&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // The user closed the editor without exporting&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // Handle the exported result here: upload it, store it,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // or hand it to the next step in your flow.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two things people miss on the first pass. &lt;code&gt;EditorPreset.video&lt;/code&gt; is what gives you the timeline; the other presets open design or photo editing with no time dimension. And &lt;code&gt;openEditor&lt;/code&gt; returns null when the user backs out, so handle that before touching the result or you will crash on cancel.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 814px) 814px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;814&quot; height=&quot;836&quot; src=&quot;https://img.ly/_astro/flutter-video-editor_kMtdo.webp&quot; srcset=&quot;/_astro/flutter-video-editor_Z1bsTWt.webp 640w, /_astro/flutter-video-editor_Z18HePF.webp 750w, /_astro/flutter-video-editor_kMtdo.webp 814w&quot;&gt;&lt;/p&gt;
&lt;p&gt;That gives users trimming, splitting, filters, text overlays, stickers, and audio.&lt;/p&gt;
&lt;p&gt;For the full configuration surface, see the &lt;a href=&quot;https://img.ly/docs/cesdk/flutter/prebuilt-solutions/video-editor-9e533a/&quot;&gt;Flutter video editor docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;building-a-tiktok-style-experience&quot;&gt;Building a TikTok-style experience&lt;/h2&gt;
&lt;p&gt;The default editor covers the basics. What turns it into a short-form video experience is the content you put behind it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trimming and timeline control.&lt;/strong&gt; Users position clips relative to each other and to audio tracks. This is the core interaction, and it is the one worth testing on a real device early, because timeline ergonomics on a phone are genuinely hard. We wrote up what we learned building ours in &lt;a href=&quot;https://img.ly/blog/designing-a-timeline-for-mobile-video-editing/&quot;&gt;designing a timeline for mobile video editing&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Filters and effects.&lt;/strong&gt; Filters set the tone, and a curated set beats an exhaustive one. Ten good looks get used; sixty get scrolled past.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Text and stickers.&lt;/strong&gt; Captions matter more than they look like they should, because most social video is watched on mute.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Music and audio.&lt;/strong&gt; A library of cleared tracks removes the biggest blocker to finishing a video.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Templates.&lt;/strong&gt; The most effective lever of the five. Build video templates in the CE.SDK web editor and deliver them to your Flutter app, so users start from something rather than an empty timeline. See the &lt;a href=&quot;https://img.ly/demos/video-ui/web/&quot;&gt;video editor demo&lt;/a&gt; for what they look like.&lt;/p&gt;
&lt;h3 id=&quot;for-influencers-and-brand-accounts&quot;&gt;For influencers and brand accounts&lt;/h3&gt;
&lt;p&gt;Branded templates let a creator drop footage and copy into a layout that already matches the brand. Watermarks keep attribution attached when the video travels off-platform.&lt;/p&gt;
&lt;h3 id=&quot;for-e-commerce-and-user-generated-content&quot;&gt;For e-commerce and user-generated content&lt;/h3&gt;
&lt;p&gt;Unboxing videos, reviews, and demos are the highest-intent content on a marketplace, and they are exactly the sort of thing people abandon if editing is awkward. The same trimming, filter, and music tools cover it.&lt;/p&gt;
&lt;h2 id=&quot;customization&quot;&gt;Customization&lt;/h2&gt;
&lt;p&gt;The Flutter plugin is designed to adapt to your brand and use case:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;UI customization.&lt;/strong&gt; Theming, color palettes, and callbacks to hook into editor events.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Video presets.&lt;/strong&gt; Constrain length or resolution to suit your target platform.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Templates.&lt;/strong&gt; Generate collages, text designs, and animations in the CE.SDK web UI and ship them to your app.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Assets.&lt;/strong&gt; Supply your own filters, fonts, and stickers. For a niche app this is often what makes the editor feel native to your community rather than generic.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Configuration options are documented in the &lt;a href=&quot;https://img.ly/docs/cesdk/flutter/configuration-2c1c3d/&quot;&gt;Flutter configuration reference&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;let-an-agent-help&quot;&gt;Let an agent help&lt;/h2&gt;
&lt;p&gt;CE.SDK ships an &lt;a href=&quot;https://img.ly/docs/cesdk/flutter/get-started/mcp-server-fde71c/&quot;&gt;MCP server&lt;/a&gt; that exposes the current documentation to AI coding tools, so an assistant can look up the real API during a session rather than reconstructing it from training data. That is worth wiring up before you start, particularly given how often the plugin version moves. Background in &lt;a href=&quot;https://img.ly/blog/img-ly-agent-skills-web/&quot;&gt;Introducing IMG.LY Agent Skills&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;Start from the &lt;a href=&quot;https://img.ly/docs/cesdk/flutter/prebuilt-solutions/video-editor-9e533a/&quot;&gt;Flutter video editor documentation&lt;/a&gt;, or try the &lt;a href=&quot;https://img.ly/demos/video-ui/web/&quot;&gt;web demo&lt;/a&gt; to see the editing model before you integrate.&lt;/p&gt;
&lt;p&gt;Shipping on more than Flutter? We have equivalent guides for &lt;a href=&quot;https://img.ly/blog/a-modern-react-video-editor/&quot;&gt;React&lt;/a&gt;, &lt;a href=&quot;https://img.ly/blog/a-modern-vue-js-video-editor/&quot;&gt;Vue.js&lt;/a&gt;, &lt;a href=&quot;https://img.ly/blog/a-modern-angular-video-editor/&quot;&gt;Angular&lt;/a&gt;, and &lt;a href=&quot;https://img.ly/blog/a-modern-video-editor-sdk-for-your-react-native-app/&quot;&gt;React Native&lt;/a&gt;. If you are still comparing vendors, we broke down the &lt;a href=&quot;https://img.ly/blog/best-video-sdks-for-mobile-applications-a-comprehensive-comparison-for-developers/&quot;&gt;video SDKs available for mobile apps&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Questions about your use case? &lt;a href=&quot;https://img.ly/forms/contact-sales/&quot;&gt;Talk to us&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>Jan</dc:creator><media:content url="https://blog.img.ly/2024/09/how-to-flutter-photo-video-design-editor-sdk.png" medium="image"/><category>Video Editing</category><category>Video Editor</category><category>Flutter</category><category>Tutorial</category><category>Learning</category></item><item><title>Designing A Timeline For Mobile Video Editing</title><link>https://img.ly/blog/designing-a-timeline-for-mobile-video-editing/</link><guid isPermaLink="true">https://img.ly/blog/designing-a-timeline-for-mobile-video-editing/</guid><description>When we brought our desktop-class video editing capabilities to iOS, we learned some interesting lessons along the way. In this article, we’ll share the key user experience learnings from our design and development process.</description><pubDate>Tue, 20 Aug 2024 13:08:58 GMT</pubDate><content:encoded>&lt;p&gt;This article documents the most surprising insights from our journey building timeline user interface. We’ll explore everything from overcoming usability challenges, visualizing data, prioritizing information, and refining touch interactions.&lt;/p&gt;
&lt;p&gt;IMG.LY’s CE.SDK for iOS now comes with a &lt;a href=&quot;https://img.ly/demos/video-ui/ios/&quot;&gt;native video editor&lt;/a&gt;, built from scratch in SwiftUI. I was responsible for coding and polishing the timeline user interface, working with both our design team and our cross-platform engine team. When I started implementing the timeline, we had the basic design concept sketched out in Figma. However, for an advanced UI like this, nothing beats rapid prototyping and iteration between design and development to make it &lt;em&gt;feel&lt;/em&gt; right.&lt;/p&gt;
&lt;h2 id=&quot;i-visualizing-time&quot;&gt;I. Visualizing Time&lt;/h2&gt;
&lt;p&gt;Timelines are a well-known convention, at least to modern humans. Timelines show durations in time as segments in space, distributed along the horizontal axis, with multiple tracks for things that happen in parallel. This is a simple yet effective way of representing moments in time visually. As obvious as it may seem today, this flavor of data visualization first appeared only 250 years ago. One of the earliest known examples is Joseph Priestley’s &lt;a href=&quot;https://en.wikipedia.org/wiki/A_Chart_of_Biography&quot;&gt;&lt;em&gt;A Chart of Biography&lt;/em&gt;&lt;/a&gt;, published in 1765. Here is Priestley’s &lt;em&gt;A New Chart of History&lt;/em&gt; from 1769, which is even more impressive:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Joseph Priestley, Public domain, via Wikimedia Commons&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 2000px) 2000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;2000&quot; height=&quot;1399&quot; src=&quot;https://img.ly/_astro/A_New_Chart_of_History_s_Z289l7s.webp&quot; srcset=&quot;/_astro/A_New_Chart_of_History_s_ZsrkiU.webp 640w, /_astro/A_New_Chart_of_History_s_ZygteI.webp 750w, /_astro/A_New_Chart_of_History_s_Z2nMk7u.webp 828w, /_astro/A_New_Chart_of_History_s_27L1WG.webp 1080w, /_astro/A_New_Chart_of_History_s_1MRp9q.webp 1280w, /_astro/A_New_Chart_of_History_s_qPD25.webp 1668w, /_astro/A_New_Chart_of_History_s_Z289l7s.webp 2000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Video editing timelines are built on this exact principle of mapping time to space: A digital video composition consists of tracks for simultaneous audio and video layers. These tracks contain individual clips that can be rearranged, trimmed, and transformed. Navigating the video’s time dimension is as easy as scrolling left and right. The tracks and clips serve as landmarks for orientation, forming the mental model of what the video composition &lt;em&gt;is&lt;/em&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Timelines map time to space&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure class=&quot;kg-embed-card&quot;&gt;
&lt;iframe src=&quot;https://www.youtube.com/embed/cKcksLW95-Y?feature=oembed&quot; title=&quot;Editing Video in Adobe Premiere 5.0 (Windows 98)&quot; loading=&quot;lazy&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;horizontal-direction&quot;&gt;Horizontal Direction&lt;/h3&gt;
&lt;p&gt;Modern iOS user interfaces appear flipped in right-to-left languages: the buttons and controls are in different horizontal positions. The layout follows the reading direction of the language. Even the familiar drill-down navigation animates to the left when drilling deeper into the hierarchy, and the &lt;em&gt;Back&lt;/em&gt; button sits in the upper right corner, its chevron pointing to the right. So, naturally, one of the first things we checked was whether timelines should run right-to-left in writing systems like Arabic or Hebrew. According to a trustworthy source, this is not the case: we found an old version of Apple’s developer guides stating that &lt;a href=&quot;https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/SupportingRight-To-LeftLanguages/SupportingRight-To-LeftLanguages.html&quot;&gt;editor timelines in software are universally left-to-right&lt;/a&gt;, even if the surrounding interface layout is flipped by the operating system for right-to-left system languages.&lt;/p&gt;
&lt;h3 id=&quot;cognitive-load-vs-discoverability&quot;&gt;Cognitive Load vs. Discoverability&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Variations of clip heights within our video timeline&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1280px) 1280px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1280&quot; height=&quot;1280&quot; src=&quot;https://img.ly/_astro/timeline_heights-s-1_1B0rL3.webp&quot; srcset=&quot;/_astro/timeline_heights-s-1_sYxV1.webp 640w, /_astro/timeline_heights-s-1_Z28nWzz.webp 750w, /_astro/timeline_heights-s-1_ZLf3iO.webp 828w, /_astro/timeline_heights-s-1_3Yibb.webp 1080w, /_astro/timeline_heights-s-1_1B0rL3.webp 1280w&quot;&gt;&lt;/p&gt;
&lt;p&gt;When designing our video timeline, we experimented with both the size of the clips and with the dimensions of the timeline itself. How much can you fit on a screen before it looks cluttered? How large can the controls be without being clumsy and inefficient? The only way to find out is to try it out right on the device.&lt;/p&gt;
&lt;p&gt;Hiding features in dropdown menus is easy. Banishing them to separate screens is even easier. But hiding functionality hurts discoverability. Out of sight, out of mind. We think user interfaces in productivity apps should be the opposite. They should prioritize &lt;a href=&quot;https://blog.codinghorror.com/information-density-and-dr-bronner/&quot;&gt;high information density&lt;/a&gt; and avoid extra navigation steps as much as possible.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1200px) 1200px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1200&quot; height=&quot;538&quot; src=&quot;https://img.ly/_astro/timeline-density_1rLStQ.webp&quot; srcset=&quot;/_astro/timeline-density_2eox0V.webp 640w, /_astro/timeline-density_Ernmb.webp 750w, /_astro/timeline-density_1MXGPB.webp 828w, /_astro/timeline-density_1dIMnl.webp 1080w, /_astro/timeline-density_1rLStQ.webp 1200w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We increased the density of the toolbar that sits below the timeline: Our goal was to make all the important features easily accessible, despite the small screen. We achieved this by changing the single floating &lt;em&gt;Add&lt;/em&gt; button from the initial designs to a more granular set of buttons to add specific asset types, like stickers and text. This not only increases efficiency for frequent users, it also makes the capabilities of the video editor more obvious and approachable.&lt;/p&gt;
&lt;h3 id=&quot;adaptive-height&quot;&gt;Adaptive Height&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Left: Small timeline in an empty scene. Right: Large timeline in a complex scene.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 2000px) 2000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;2000&quot; height=&quot;2089&quot; src=&quot;https://img.ly/_astro/scenes-empty-full-s_5B3si.webp&quot; srcset=&quot;/_astro/scenes-empty-full-s_CfAiv.webp 640w, /_astro/scenes-empty-full-s_ZfAn0W.webp 750w, /_astro/scenes-empty-full-s_Z1SbLyW.webp 828w, /_astro/scenes-empty-full-s_oqPCk.webp 1080w, /_astro/scenes-empty-full-s_Z1E4aGO.webp 1280w, /_astro/scenes-empty-full-s_1pGwkF.webp 1668w, /_astro/scenes-empty-full-s_5B3si.webp 2000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;As space is at a premium on a small screen, we wanted to make the video preview as large as possible. We decided to allow the user to collapse the timeline at any time to focus on the video canvas. And even without manually minimizing the timeline, it doesn’t waste space: the timeline adjusts its height to fit snugly around its contents. It only grows as you add more clips.&lt;/p&gt;
&lt;h3 id=&quot;units-and-scale&quot;&gt;Units and Scale&lt;/h3&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/building-a-timeline/zoom-levels.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;The numeric scale is an essential part of any timeline. It helps you see the &lt;em&gt;in&lt;/em&gt; and &lt;em&gt;out&lt;/em&gt; time of a clip at a glance, and the permanently visible ruler makes changes in the zoom level easy to understand. We added dots as subdivisions between the ruler’s numeric labels, which gives it a nice tool-like character. At full zoom (when the ruler shows 5-second intervals), we decided to use four dots in between, so there is one dot for each second. We think this detail adds a welcome sense of precision.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/building-a-timeline/clip-label.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;The clips themselves have a duration label when they are selected. If the duration is below 10, you get a fractional digit (e.g., 4.2s). For the ruler, we went with the same short format (5s, 10s, 30s, etc.) for all values below one minute, and the technical format (1:00, 1:30, etc.) for the rest. Of course, we use iOS’s built-in &lt;a href=&quot;https://swiftbysundell.com/articles/formatting-numbers-in-swift/&quot;&gt;number formatters&lt;/a&gt; to get properly formatted and localized strings for our labels.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/building-a-timeline/ruler-rounding.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;An important detail for the label that shows the current playback timecode: The seconds must always be rounded down. If the playhead sits between two seconds, the lower number must be displayed until the playhead crosses the indicator for the higher second. Simple rounding to the nearest integer would be confusing, because it doesn’t match our expectations when dealing with timelines. Five seconds do not count as five seconds until they have elapsed in their entirety.&lt;/p&gt;
&lt;h2 id=&quot;ii-manipulating-time&quot;&gt;II. Manipulating Time&lt;/h2&gt;
&lt;p&gt;What &lt;em&gt;looks&lt;/em&gt; good is not guaranteed to &lt;em&gt;feel&lt;/em&gt; good when you interact with it. A video editor timeline is more than just a visualization; it’s also a user interface. As such, it should be self-explanatory and provide constant feedback as the user manipulates it.&lt;/p&gt;
&lt;h3 id=&quot;fingertip-sized&quot;&gt;Fingertip-sized&lt;/h3&gt;
&lt;p&gt;The clips must be large enough to be easy to touch and at the same time detailed enough to give a decent overview. The size that can be easily tapped by most people &lt;a href=&quot;https://www.nngroup.com/articles/touch-target-size/&quot;&gt;is around one square centimeter&lt;/a&gt;, which matches the 44 × 44 pt default size of iPhone system controls. Our testing showed that we could go a little smaller. Editing video is a focused task, so the tap targets don’t need to be as robust as for tasks that happen while you, say, run for the bus. And all user interfaces should be scalable for accessibility anyhow, so we didn’t hard-code any sizes and we also made the dimensions adjustable. And, speaking of adapting to individual user needs: of course, all the text labels in our timeline are &lt;a href=&quot;https://developer.apple.com/documentation/uikit/scaling-fonts-automatically&quot;&gt;automatically scaled&lt;/a&gt; depending on your device settings.&lt;/p&gt;
&lt;h3 id=&quot;handles&quot;&gt;Handles&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Hit area of timeline handles&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1179px) 1179px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1179&quot; height=&quot;438&quot; src=&quot;https://img.ly/_astro/hit-area_oz7lQ.webp&quot; srcset=&quot;/_astro/hit-area_1upm7s.webp 640w, /_astro/hit-area_Z13oSY4.webp 750w, /_astro/hit-area_Z1F41vl.webp 828w, /_astro/hit-area_ZSe7PG.webp 1080w, /_astro/hit-area_oz7lQ.webp 1179w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Selected clips in the timeline get a bold blue frame with large handles on either side. These handles are used to trim the clip’s length. For comfortable tapping and dragging, the handles must be larger than their visual size. In fact, we made the hit area more than twice as wide as the visual appearance suggests.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Triangular indents on trim handles&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 500px) 500px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;500&quot; height=&quot;500&quot; src=&quot;https://img.ly/_astro/triangle_ZpqMCy.webp&quot; srcset=&quot;/_astro/triangle_ZpqMCy.webp 500w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Early on in our design process, we realized that the trim handles had to sit on the outside of the clip, extending beyond the left and right edge. This made it hard to see the clip’s actual size, so we added little grooves: little triangular indents that point to the start and end of the selected clip.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/building-a-timeline/clip-trim-bounce.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Some clips in the timeline can be extended to any duration, like text or stickers. Other clips have a finite footage duration, like video and audio clips. To make this difference visible, clips with a finite footage duration reveal a ghost outline in the background while they are resized, featuring &lt;a href=&quot;https://en.wikipedia.org/wiki/Marching_ants&quot;&gt;marching ants&lt;/a&gt;. The handle icon changes from an outward-pointing chevron to a vertical line when the clip can’t be made longer.&lt;/p&gt;
&lt;h3 id=&quot;scrolling-and-zooming&quot;&gt;Scrolling and Zooming&lt;/h3&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/building-a-timeline/scroll-zoom.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;A rather invisible detail was one of the trickiest things to get right: the coordination of all the different finger gestures on the timeline.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Horizontal Scrolling:&lt;/strong&gt; Timeline scrolls horizontally to move in time.&lt;br&gt;
&lt;strong&gt;Vertical Scrolling:&lt;/strong&gt; Timeline scrolls vertically providing room for tracks.&lt;br&gt;
&lt;strong&gt;Clip Movement:&lt;/strong&gt; Dragging horizontally on a selected clip moves it.&lt;br&gt;
&lt;strong&gt;Duration Adjustment:&lt;/strong&gt; Dragging the trim handles adjusts the clip’s duration.&lt;br&gt;
&lt;strong&gt;Pinch-to-Zoom:&lt;/strong&gt; Pinching with two fingers changes the zoom level of the visualization.&lt;/p&gt;
&lt;p&gt;All these gestures must behave as expected and not interfere with each other. We found it unexpectedly difficult to fine-tune and harmonize these interactions with pure SwiftUI, so we used some proven legacy iOS techniques to get it right. If you’re interested in the technical details of our solution with &lt;code&gt;SwiftUIIntrospect&lt;/code&gt; and &lt;code&gt;UIGestureRecognizers&lt;/code&gt;, check the &lt;a href=&quot;https://github.com/imgly/IMGLYUI-swift/tree/main/Sources/IMGLYEditor/Timeline/TimelineView&quot;&gt;source code&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;snapping&quot;&gt;Snapping&lt;/h3&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/building-a-timeline/snapping.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Video editing must feel precise, even on a small screen. When you trim or move clips, they should snap to other clips, to the playhead, and to the start and the end of the timeline. To show which position the selected clip snaps to, we designed animated dotted lines. We use the iPhone’s haptic engine to provide subtle feedback for snapping, which really helps to make the interaction feel natural, like a notch snapping into a detent. Something that we didn’t get right at first: Snapping should only respect those snapping points that are currently visible in the viewport. Of course! Otherwise, a partially visible clip may snap to something offscreen, which is very confusing.&lt;/p&gt;
&lt;h3 id=&quot;scrubbing-preview&quot;&gt;Scrubbing Preview&lt;/h3&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/building-a-timeline/scrubbing.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;For editing a video clip to feel precise, you need to be able to see exactly &lt;em&gt;where&lt;/em&gt; you’re trimming. But the playback position in our mobile timeline can’t change while you’re trimming, because that would mean scrolling the timeline, which would move the very clip you’re trimming. The trim preview needs to be independent of the composition’s playback position. We solved this by adding a temporary overlay with its own playback time to the canvas. When you start dragging one of the handles on either side of the clip, the overlay shows the exact trim position of the video clip. When you release, the preview returns to the playback position.&lt;/p&gt;
&lt;h2 id=&quot;try-it-out&quot;&gt;Try it out!&lt;/h2&gt;
&lt;p&gt;“The only way to experience an experience is to experience it,” said interaction designer Bill Moggridge, and we couldn’t agree more! If you’re curious how our new video timeline &lt;em&gt;feels&lt;/em&gt;, &lt;a href=&quot;https://apps.apple.com/en/app/img-ly-design-editor/id1672991141&quot;&gt;download our iOS app&lt;/a&gt; and try editing your own videos in our brand-new timeline experience.&lt;/p&gt;
&lt;p&gt;If you’re a developer, check out &lt;a href=&quot;https://img.ly/docs/cesdk/ios/starterkits/video-editor-e1nlor/&quot;&gt;the video editor documentation&lt;/a&gt;. With IMG.LY’s SDK, you can add all of these video editing capabilities to your own apps in a breeze.&lt;/p&gt;
&lt;p&gt;And if you are weighing this against building the timeline yourself, or against another vendor, we compared the &lt;a href=&quot;https://img.ly/blog/best-video-sdks-for-mobile-applications-a-comprehensive-comparison-for-developers/&quot;&gt;video SDKs available for mobile apps&lt;/a&gt; on the details that matter once you get past the demo.&lt;/p&gt;</content:encoded><dc:creator>Frank</dc:creator><media:content url="https://blog.img.ly/2024/08/build-a-timeline-video-app-s.jpg" medium="image"/><category>App Development</category><category>UI/UX</category><category>Video Editing</category><category>Video Editor</category><category>Insights</category></item><item><title>CE.SDK v1.21 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v-1-21-0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v-1-21-0-release-notes/</guid><description>Create stunning videos using a brand-new timeline for web.</description><pubDate>Thu, 22 Feb 2024 16:22:28 GMT</pubDate><content:encoded>&lt;p&gt;Since our &lt;a href=&quot;https://img.ly/blog/creative-editor-sdk-v_1_20_0-release-notes/&quot;&gt;last release&lt;/a&gt;, we’ve been crafting new features to empower your users’ creative journey. Today, we are happy to introduce CE.SDK v1.21!&lt;/p&gt;
&lt;h3 id=&quot;create-videos-with-a-new-timeline-for-web&quot;&gt;Create Videos With A New Timeline for Web&lt;/h3&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-21/video-for-web-121-s.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Create eye-catching videos within your web app for any platform, including Instagram, TikTok, or YouTube! Here’s what’s new: the integrated &lt;strong&gt;timeline&lt;/strong&gt; supports the arrangement of elements like videos, photos, text, audio, shapes and stickers. Users can fine-tune their projects with adjustments or filters, and personalize their creations with audio from a customizable library.&lt;/p&gt;
&lt;p&gt;To simplify your content creation, use our formats that automatically &lt;strong&gt;set your canvas size&lt;/strong&gt; &lt;strong&gt;for social media&lt;/strong&gt; and other popular video resolutions.&lt;/p&gt;
&lt;p&gt;Effectively &lt;strong&gt;arrange&lt;/strong&gt; and edit multiple elements within your videos, offering precise control over the editing process. Easily split, trim, and replace. Lastly, make it pop by adding audio files to the composition.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Refine designs in our Showcase by customizing templates: adjust filters, swap visuals or audio, including integration with Soundstripe for premium stock audio.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1964px) 1964px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1964&quot; height=&quot;1468&quot; src=&quot;https://img.ly/_astro/grafik-1_Z2vcpw2.webp&quot; srcset=&quot;/_astro/grafik-1_l6R8S.webp 640w, /_astro/grafik-1_1VcVR5.webp 750w, /_astro/grafik-1_28E4m7.webp 828w, /_astro/grafik-1_6eeDG.webp 1080w, /_astro/grafik-1_FXFIo.webp 1280w, /_astro/grafik-1_Zupm2H.webp 1668w, /_astro/grafik-1_Z2vcpw2.webp 1964w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Creating &lt;strong&gt;templates&lt;/strong&gt; with placeholders for your users is just as easy. Simply select an element, click ‘Placeholder’, and decide which elements can be edited.&lt;/p&gt;
&lt;p&gt;To integrate, browse our &lt;a href=&quot;https://img.ly/docs/cesdk/js/starterkits/video-editor-e1nlor/&quot;&gt;Guide&lt;/a&gt;. Try the &lt;a href=&quot;https://img.ly/demos/video-ui/web/&quot;&gt;video editor live demo&lt;/a&gt; yourself. This showcase contains templates, audio and video examples for you to try.&lt;/p&gt;
&lt;h3 id=&quot;keep-designs-in-focus-on-ios&quot;&gt;Keep Designs in Focus on iOS&lt;/h3&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-21/iOS-zoom-apparel-designer-sdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Our new Camera Zoom Limits make editing a design easier. Your page stays in focus to &lt;strong&gt;avoid accidental scrolling&lt;/strong&gt; outside the design. The zoom level is set within a minimum and maximum range, ensuring a practical, usable view at all times. When you select an element in your design, it stays in focus when opening adjustments or other inspectors. It allows you to immediately see changes made to the selected element. This improvement is available for iOS and Android, and can be tested in our Design Editor Demo on the &lt;a href=&quot;https://apps.apple.com/de/app/img-ly-design-editor/id1672991141&quot;&gt;App Store&lt;/a&gt; and &lt;a href=&quot;https://play.google.com/store/apps/details?id=ly.img.cesdk.catalog&quot;&gt;Google Play&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;ensure-color-purity-in-print&quot;&gt;Ensure Color Purity in Print&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/1-12_underlayer_17BKwF.webp&quot; srcset=&quot;/_astro/1-12_underlayer_1H76HF.webp 640w, /_astro/1-12_underlayer_1QF3eC.webp 750w, /_astro/1-12_underlayer_b0yHf.webp 828w, /_astro/1-12_underlayer_Z2ex2Iz.webp 1080w, /_astro/1-12_underlayer_ZxWD5W.webp 1280w, /_astro/1-12_underlayer_17BKwF.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Our newly introduced &lt;strong&gt;Underlayer API&lt;/strong&gt; guarantees the preservation of color purity whenever you export designs using our CE.SDK for print. This solution specifically addresses the challenge of maintaining the richness and vibrancy of colors, irrespective of the color of the canvas, which could range from apparel to paper.&lt;/p&gt;
&lt;p&gt;When you’re ready to export your design, this feature adds a special ‘&lt;strong&gt;underbase&lt;/strong&gt;’ layer, underneath your design. This layer, typically a white or specific primer coat, makes sure the final printed colors match your original vision perfectly.&lt;/p&gt;
&lt;h3 id=&quot;very-soon-integrate-short-form-video-creation&quot;&gt;Very soon: Integrate Short-Form Video Creation&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1920px) 1920px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1920&quot; height=&quot;1080&quot; src=&quot;https://img.ly/_astro/VCC_head-loading_s_1xv7Su.webp&quot; srcset=&quot;/_astro/VCC_head-loading_s_1zfTbL.webp 640w, /_astro/VCC_head-loading_s_1eaEga.webp 750w, /_astro/VCC_head-loading_s_1zCrl9.webp 828w, /_astro/VCC_head-loading_s_1bkK2a.webp 1080w, /_astro/VCC_head-loading_s_ZLHGbo.webp 1280w, /_astro/VCC_head-loading_s_Z2gQyd9.webp 1668w, /_astro/VCC_head-loading_s_1xv7Su.webp 1920w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Video remains key for attracting, engaging and retaining audiences, especially on mobile. Creating a video editor can be tough, thus we’re thrilled to soon release our turnkey solution for &lt;strong&gt;mobile video content creation&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Combined with our new &lt;a href=&quot;https://img.ly/products/video-sdk-mobile/&quot;&gt;Camera SDK&lt;/a&gt;, users can seamlessly blend video, audio, text, and graphics on a sleek timeline. It includes features like voiceover, zoom, tap to record, and the popular split screen modes for reactions and duets. You may recognize these from Instagram or TikTok!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Last chance:&lt;/strong&gt; &lt;strong&gt;Secure your waitlist spot&lt;/strong&gt; to our Video Content Creation Release. You will also receive access to our TestFlight app.&lt;br&gt;
Registration is only open until March 6, 2024.&lt;/p&gt;
&lt;p&gt;? &lt;a href=&quot;https://share.hsforms.com/1mrIXiBbURn6sMqYgZG9c6A1hk3i&quot;&gt;Gain Access&lt;/a&gt; to our Video Content Creation Release&lt;br&gt;
? &lt;a href=&quot;https://2498814.fs1.hubspotusercontent-na1.net/hubfs/2498814/Newsletter-Digest/nov-2023/IMGLY_VIDEO_SDK.pdf?utm_campaign=Video%20Content%20Creation&amp;#x26;utm_medium=releasenotes&amp;#x26;_hsmi=2&amp;#x26;utm_content=2&amp;#x26;utm_source=blog&quot;&gt;Download Feature Exposé&lt;/a&gt; instantly (PDF)&lt;/p&gt;
&lt;p&gt;We can’t wait to hear your feedback!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thanks for reading. Join over 3000 specialists with powerful apps, and&lt;/strong&gt; &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;&lt;strong&gt;subscribe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to our newsletter. We keep you in the loop with brand-new features and updates.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Neslihan</dc:creator><media:content url="https://blog.img.ly/2024/02/video-web-editor-sdk-imgly-s.jpg" medium="image"/><category>Release Notes</category><category>Video Editing</category><category>Video Editor</category><category>Web-to-print</category><category>Print</category><category>iOS App Development</category></item><item><title>How To Build a Video Editor With Wasm in React</title><link>https://img.ly/blog/how-to-build-a-video-editor-with-wasm-in-react/</link><guid isPermaLink="true">https://img.ly/blog/how-to-build-a-video-editor-with-wasm-in-react/</guid><description>Use the ffmpeg.wasm library to build a React video editor that performs video processing directly in the browser.</description><pubDate>Mon, 16 Jan 2023 16:31:57 GMT</pubDate><content:encoded>&lt;p&gt;You may think that video processing can only be performed on a server, but this is not true. Thanks to WebAssembly (Wasm), you can run high-performance code written in C or C++ in your browser. This opens up a lot of possibilities and gives you the ability to build a client-side video editor. Let’s now learn how to create a Wasm-based video editor in React.&lt;/p&gt;
&lt;p&gt;Follow this tutorial and learn how to build the application below:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Upload and crop your video, and covert it as a GIF&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 671px) 671px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;671&quot; height=&quot;943&quot; src=&quot;https://img.ly/_astro/ffmpeg-video-editor-wasm_1Wlxwn.webp&quot; srcset=&quot;/_astro/ffmpeg-video-editor-wasm_Z1NFE9C.webp 640w, /_astro/ffmpeg-video-editor-wasm_1Wlxwn.webp 671w&quot;&gt;&lt;/p&gt;
&lt;p&gt;This React video editor allows users to upload a video, select a portion of it, convert it to GIF, and download the resulting image file – all of this in your browser.&lt;/p&gt;
&lt;h2 id=&quot;what-is-webassembly&quot;&gt;What is WebAssembly?&lt;/h2&gt;
&lt;p&gt;WebAssembly (also called Wasm) is a new type of code that modern web browsers can run and understand. Specifically, Wasm provides new functionality to web development and brings significant performance benefits. This applies to both frontend and backend, since Wasm can be used by both clients and servers.&lt;/p&gt;
&lt;p&gt;Wasm code should not be written by hand. This is because Wasm is a binary instruction format. So, Wasm is designed to be a compilation target for source languages such as C, C++, Rust, and others. Learn more about Wasm on the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/WebAssembly&quot;&gt;WebAssembly MDN Web Docs page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Wasm provides a way to run code written in several languages on the Web at near-native speed. This means that WebAssembly forms can be easily imported and executed by a Web client or server application. In other words, you can use WebAssembly functions via JavaScript and achieve results that were not previously possible on a browser, especially in terms of performance.&lt;/p&gt;
&lt;h2 id=&quot;what-is-ffmpegwasm&quot;&gt;What is &lt;code&gt;ffmpeg.wasm&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;As stated on the &lt;a href=&quot;https://github.com/ffmpegwasm/ffmpeg.wasm&quot;&gt;GitHub page of the project&lt;/a&gt;, &lt;code&gt;ffmpeg.wasm&lt;/code&gt; is a WebAssembly and JavaScript port of FFmpeg. If you are not familiar with it, FFmpeg is an open-source software suite that includes several libraries and programs for managing audio, video, streams, and other media files. All of these tools can be invoked and executed via the &lt;code&gt;ffmpeg&lt;/code&gt; command-line instruction.&lt;/p&gt;
&lt;p&gt;Therefore, &lt;code&gt;ffmpeg.wasm&lt;/code&gt; enables video and audio processing in JavaScript-based web applications. In detail, it enables video and audio recording, format transcoding, video and audio editing, and video scaling. Even though it is a WebAssembly-based library, you can use it in your JavaScript code just like any other &lt;code&gt;npm&lt;/code&gt; library. This is the power of Wasm.&lt;/p&gt;
&lt;p&gt;Since it transpiles to Wasm, you can take advantage of &lt;code&gt;ffmpeg.wasm&lt;/code&gt; directly in your browser without performance concerns. This means that &lt;code&gt;ffmpeg.wasm&lt;/code&gt; opens the door to client-side audio and video processing. Let’s now learn how to use &lt;code&gt;ffmpeg.wasm&lt;/code&gt; to build a client-side video editor in React!&lt;/p&gt;
&lt;h2 id=&quot;building-a-video-editor-in-react-with-wasm&quot;&gt;Building a Video Editor in React with WASM&lt;/h2&gt;
&lt;p&gt;In this step-by-step tutorial, you will learn how to build a Wasm-based video editor in React with &lt;code&gt;ffmpeg.wasm&lt;/code&gt;. This React video editor application will allow you to upload a video, trim it, and convert it to GIF in the browser, without using any backend functionality or external API.&lt;/p&gt;
&lt;p&gt;Clone the &lt;a href=&quot;https://github.com/imgly/video-editor-wasm-react&quot;&gt;GitHub repository that supports the tutorial&lt;/a&gt; and try the video editor application by launching the following commands:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;git clone https://github.com/Tonel/video-editor-wasm-react&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cd video-editor-wasm-react&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm install&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm run start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s waste no more time and see how to build a video editor application in React.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;
&lt;p&gt;This is the list of libraries the video editor application you are about to build depends on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/download/package-manager&quot;&gt;Node.js and npm 8+ and higher&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/facebook/react/blob/main/CHANGELOG.md#1820-june-14-2022&quot;&gt;React 18.2+&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[ffmpeg.wasm](https://github.com/ffmpegwasm/ffmpeg.wasm)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[antd](https://www.npmjs.com/package/antd)&lt;/code&gt; &gt;= 4.3&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[video-react](https://www.npmjs.com/package/video-react)&lt;/code&gt; &gt;= 0.15&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;antd&lt;/code&gt; is one of the most popular UI libraries for React. In this tutorial, its &lt;code&gt;[Slider](https://ant.design/components/slider/)&lt;/code&gt; component will be used to implement the video cutting feature. So, any other UI library including a slider component with a &lt;code&gt;range&lt;/code&gt; option will do.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;video-react&lt;/code&gt; is one of the most advanced and reliable HTML5 video players for React. You can replace it with any other React video player library.&lt;/p&gt;
&lt;h3 id=&quot;initializing-a-react-project&quot;&gt;Initializing a React Project&lt;/h3&gt;
&lt;p&gt;Let’s initialize a new &lt;a href=&quot;https://create-react-app.dev/docs/getting-started/&quot;&gt;Create React App&lt;/a&gt; React project called &lt;code&gt;video-editor-wasm-react&lt;/code&gt; with the command below:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npx create-react-app video-editor-wasm-react&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your &lt;code&gt;video-editor-wasm-react&lt;/code&gt; directory should now contain the following files:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;video-editor-wasm-react&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── README.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── node_modules&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── package.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── .gitignore&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── public&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── favicon.ico&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── index.html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── logo192.png&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── logo512.png&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── manifest.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   └── robots.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;└── src&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── App.css&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── App.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── App.test.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── index.css&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── index.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── logo.svg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── reportWebVitals.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    └── setupTests.js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Enter the &lt;code&gt;video-editor-wasm-react&lt;/code&gt; folder in your terminal and launch a React local server with the commands below:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cd video-editor-wasm-react&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, visit the &lt;code&gt;[http://localhost:3000/](http://localhost:3000/)&lt;/code&gt; page in your browser, and you should be seeing the default Create React App screen.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The default Create React App screen&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 983px) 983px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;983&quot; height=&quot;728&quot; src=&quot;https://img.ly/_astro/s_D2E103F8349A30F6AA8E27CD2BA4B6EDB946A8DEF5B8272009321B4F51D679F9_1624366125534_image_ZnRHUs.webp&quot; srcset=&quot;/_astro/s_D2E103F8349A30F6AA8E27CD2BA4B6EDB946A8DEF5B8272009321B4F51D679F9_1624366125534_image_Z27cfRw.webp 640w, /_astro/s_D2E103F8349A30F6AA8E27CD2BA4B6EDB946A8DEF5B8272009321B4F51D679F9_1624366125534_image_PKHdG.webp 750w, /_astro/s_D2E103F8349A30F6AA8E27CD2BA4B6EDB946A8DEF5B8272009321B4F51D679F9_1624366125534_image_Z2jJD5k.webp 828w, /_astro/s_D2E103F8349A30F6AA8E27CD2BA4B6EDB946A8DEF5B8272009321B4F51D679F9_1624366125534_image_ZnRHUs.webp 983w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Before installing &lt;code&gt;ffmpeg.wasm&lt;/code&gt;, you need to get your server ready. As stated &lt;a href=&quot;https://github.com/ffmpegwasm/ffmpeg.wasm#installation&quot;&gt;in the official documentation&lt;/a&gt;, &lt;code&gt;fmmpeg.wasm&lt;/code&gt; depends on &lt;code&gt;[SharedArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer)&lt;/code&gt;. This means that only browsers that support &lt;code&gt;SharedArrayBuffer&lt;/code&gt; can run &lt;code&gt;ffmpeg.wasm&lt;/code&gt;. You can find a complete list of all browsers &lt;a href=&quot;https://caniuse.com/sharedarraybuffer&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the most popular browsers, &lt;code&gt;SharedArrayBuffer&lt;/code&gt; is only available to &lt;a href=&quot;https://developer.chrome.com/blog/enabling-shared-array-buffer/#cross-origin-isolation&quot;&gt;cross-origin isolated&lt;/a&gt; webpages. To enable this, you need to set the following headers in your server hosting the React application:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Cross-Origin-Embedder-Policy: require-corp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Cross-Origin-Opener-Policy: same-origin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In a Create-React-App application, you achieve this by creating a &lt;code&gt;src/setupProxy.js&lt;/code&gt; file and making sure it contains the following code:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;module.exports = function (app) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    app.use(function (req, res, next) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        res.setHeader(&quot;Cross-Origin-Opener-Policy&quot;, &quot;same-origin&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        res.setHeader(&quot;Cross-Origin-Embedder-Policy&quot;, &quot;require-corp&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        next()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your local development server is now ready to use &lt;code&gt;ffmpeg.wasm&lt;/code&gt;!&lt;/p&gt;
&lt;h3 id=&quot;installing-the-projects-dependencies&quot;&gt;Installing the Project’s Dependencies&lt;/h3&gt;
&lt;p&gt;It is now time to add the aforementioned required dependencies to your project.&lt;/p&gt;
&lt;p&gt;First, install &lt;code&gt;ffmpeg.wasm&lt;/code&gt; with the following command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm install @ffmpeg/ffmpeg @ffmpeg/core&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, let’s install &lt;a href=&quot;https://ant.design/&quot;&gt;Antd Design&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm install antd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, it is time to install &lt;a href=&quot;https://video-react.js.org/&quot;&gt;Video-React&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm install video-react redux&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that &lt;code&gt;video-react&lt;/code&gt; also requires &lt;code&gt;[redux](https://www.npmjs.com/package/redux)&lt;/code&gt; to work.&lt;/p&gt;
&lt;p&gt;You have now everything you need to start developing your React video editor!&lt;/p&gt;
&lt;h3 id=&quot;uploading-a-video-to-the-video-editor&quot;&gt;Uploading a Video to the Video Editor&lt;/h3&gt;
&lt;p&gt;Create a &lt;code&gt;VideoUpload&lt;/code&gt; component as below:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// src/components/VideoUpload.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { Button, Upload } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;antd&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; VideoUpload&lt;/span&gt;&lt;span&gt;({ &lt;/span&gt;&lt;span&gt;disabled&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;onChange&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {}, &lt;/span&gt;&lt;span&gt;onRemove&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {} }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;Upload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        disabled&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{disabled}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        beforeUpload&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          return&lt;/span&gt;&lt;span&gt; false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        accept&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;video/*&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        onChange&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;info&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          if&lt;/span&gt;&lt;span&gt; (info.fileList &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; info.fileList.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span&gt; &gt;&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onChange&lt;/span&gt;&lt;span&gt;(info.fileList[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;].originFileObj);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        showUploadList&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;&lt;/span&gt;&lt;span&gt;Button&lt;/span&gt;&lt;span&gt;&gt;Upload Video&amp;#x3C;/&lt;/span&gt;&lt;span&gt;Button&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span&gt;Upload&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;Button&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        danger&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        disabled&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;disabled}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        onClick&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          onRemove&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        Remove&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span&gt;Button&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; VideoUpload;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, this component uses the &lt;a href=&quot;https://ant.design/components/upload/&quot;&gt;Antd Design Upload&lt;/a&gt; component to allow users to upload a video file. Then, a “Remove” button gives users the ability to remove the uploaded video. Note that when the &lt;code&gt;Upload&lt;/code&gt; component is enabled, the “Remove” button is disabled and vice versa. This way, users can deal with only one video at a time.&lt;/p&gt;
&lt;h3 id=&quot;playing-a-video-in-react&quot;&gt;Playing a Video in React&lt;/h3&gt;
&lt;p&gt;You now need a &lt;code&gt;VideoPlayer&lt;/code&gt; component to play the uploaded video. You can build it as below:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// src/components/VideoPlayer.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  BigPlayButton,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ControlBar,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  LoadingSpinner,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Player,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  PlayToggle,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;video-react&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;video-react/dist/video-react.css&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { useEffect, useState } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;react&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; VideoPlayer&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  src&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  onPlayerChange&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  onChange&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  startTime&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; undefined&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;player&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setPlayer&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useState&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;playerState&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setPlayerState&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useState&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  useEffect&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (playerState) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      onChange&lt;/span&gt;&lt;span&gt;(playerState);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, [playerState]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  useEffect&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    onPlayerChange&lt;/span&gt;&lt;span&gt;(player);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (player) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      player.&lt;/span&gt;&lt;span&gt;subscribeToStateChange&lt;/span&gt;&lt;span&gt;(setPlayerState);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, [player]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&apos;video-player&apos;&lt;/span&gt;&lt;span&gt;}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;Player&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        ref&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;player&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          setPlayer&lt;/span&gt;&lt;span&gt;(player);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        startTime&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{startTime}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;&lt;/span&gt;&lt;span&gt;source&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{src} /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;&lt;/span&gt;&lt;span&gt;BigPlayButton&lt;/span&gt;&lt;span&gt; position&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;center&quot;&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;&lt;/span&gt;&lt;span&gt;LoadingSpinner&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;&lt;/span&gt;&lt;span&gt;ControlBar&lt;/span&gt;&lt;span&gt; autoHide&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;disableDefaultControls&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          &amp;#x3C;&lt;/span&gt;&lt;span&gt;PlayToggle&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;/&lt;/span&gt;&lt;span&gt;ControlBar&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span&gt;Player&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a simple &lt;code&gt;video-react&lt;/code&gt;-based video player component, which only allows playing or stop the video file received with the &lt;code&gt;src&lt;/code&gt; prop.&lt;/p&gt;
&lt;h3 id=&quot;cutting-a-video-in-react&quot;&gt;Cutting a Video in React&lt;/h3&gt;
&lt;p&gt;Your goal is to allow users to select a portion of the video and watch it before converting it into GIF. Implement this with the logic below:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { Slider } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &quot;antd&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { sliderValueToVideoTime } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &quot;../utils/utils&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; VideoEditor&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;sliderValues&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setSliderValues&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useState&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // logic to handle videoFile, videoPlayer, and videoPlayerState...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  useEffect&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; min&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sliderValues[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // when the slider values are updated, updating the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // video time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      if&lt;/span&gt;&lt;span&gt; (min &lt;/span&gt;&lt;span&gt;!==&lt;/span&gt;&lt;span&gt; undefined&lt;/span&gt;&lt;span&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; videoPlayerState &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; videoPlayer) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          videoPlayer.&lt;/span&gt;&lt;span&gt;seek&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sliderValueToVideoTime&lt;/span&gt;&lt;span&gt;(videoPlayerState.duration, min))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, [sliderValues])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  useEffect&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      if&lt;/span&gt;&lt;span&gt; (videoPlayer &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; videoPlayerState) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          // allowing users to watch only the portion of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          // the video selected by the slider&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;min&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;max&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; sliderValues&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          const&lt;/span&gt;&lt;span&gt; minTime&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sliderValueToVideoTime&lt;/span&gt;&lt;span&gt;(videoPlayerState.duration, min)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          const&lt;/span&gt;&lt;span&gt; maxTime&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sliderValueToVideoTime&lt;/span&gt;&lt;span&gt;(videoPlayerState.duration, max)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          if&lt;/span&gt;&lt;span&gt; (videoPlayerState.currentTime &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; minTime) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              videoPlayer.&lt;/span&gt;&lt;span&gt;seek&lt;/span&gt;&lt;span&gt;(minTime)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          if&lt;/span&gt;&lt;span&gt; (videoPlayerState.currentTime &lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; maxTime) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              // looping logic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              videoPlayer.&lt;/span&gt;&lt;span&gt;seek&lt;/span&gt;&lt;span&gt;(minTime)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, [videoPlayerState])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          // other video editor components...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          &amp;#x3C;&lt;/span&gt;&lt;span&gt;Slider&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            disabled&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;videoPlayerState}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{sliderValues}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            range&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onChange&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;values&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              setSliderValues&lt;/span&gt;&lt;span&gt;(values)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            tooltip&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              formatter: &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This component equips users with the ability to select a portion of the uploaded video with the Antd Design &lt;code&gt;Slider&lt;/code&gt; component and watch it in loop, before converting it into a GIF file.&lt;/p&gt;
&lt;p&gt;Specifically, the logic here uses the &lt;code&gt;sliderValueToVideoTime()&lt;/code&gt; function below to transform the slider values into time coordinates:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// src/utils/utils.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export function sliderValueToVideoTime(duration, sliderValue) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return Math.round(duration * sliderValue / 100)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that the actual video processing slider will be performed by the next component through &lt;code&gt;ffmpeg&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;converting-a-video-to-gif-in-react&quot;&gt;Converting a Video to GIF in React&lt;/h3&gt;
&lt;p&gt;To convert a video to GIF, create a &lt;code&gt;VideoConversionButton&lt;/code&gt; component as follows:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// src/components/VideoConversionButton.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { Button } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;antd&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { fetchFile } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@ffmpeg/ffmpeg&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { sliderValueToVideoTime } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;../utils/utils&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; VideoConversionButton&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  videoPlayerState&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  sliderValues&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  videoFile&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ffmpeg&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  onConversionStart&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  onConversionEnd&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  onGifCreated&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; convertToGif&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; async&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // starting the conversion process&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    onConversionStart&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; inputFileName&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &apos;gif.mp4&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; outputFileName&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &apos;output.gif&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // writing the video file to memory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ffmpeg.&lt;/span&gt;&lt;span&gt;FS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;writeFile&apos;&lt;/span&gt;&lt;span&gt;, inputFileName, &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; fetchFile&lt;/span&gt;&lt;span&gt;(videoFile));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;min&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;max&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; sliderValues;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; minTime&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sliderValueToVideoTime&lt;/span&gt;&lt;span&gt;(videoPlayerState.duration, min);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; maxTime&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sliderValueToVideoTime&lt;/span&gt;&lt;span&gt;(videoPlayerState.duration, max);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // cutting the video and converting it to GIF with an FFMpeg command&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    await&lt;/span&gt;&lt;span&gt; ffmpeg.&lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &apos;-i&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      inputFileName,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &apos;-ss&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      `${&lt;/span&gt;&lt;span&gt;minTime&lt;/span&gt;&lt;span&gt;}`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &apos;-to&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      `${&lt;/span&gt;&lt;span&gt;maxTime&lt;/span&gt;&lt;span&gt;}`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &apos;-f&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &apos;gif&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      outputFileName&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // reading the resulting file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; ffmpeg.&lt;/span&gt;&lt;span&gt;FS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;readFile&apos;&lt;/span&gt;&lt;span&gt;, outputFileName);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // converting the GIF file created by FFmpeg to a valid image URL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; gifUrl&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; URL&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;createObjectURL&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      new&lt;/span&gt;&lt;span&gt; Blob&lt;/span&gt;&lt;span&gt;([data.buffer], { type: &lt;/span&gt;&lt;span&gt;&apos;image/gif&apos;&lt;/span&gt;&lt;span&gt; })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    onGifCreated&lt;/span&gt;&lt;span&gt;(gifUrl);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // ending the conversion process&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    onConversionEnd&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;Button&lt;/span&gt;&lt;span&gt; onClick&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; convertToGif&lt;/span&gt;&lt;span&gt;()}&gt;Convert to GIF&amp;#x3C;/&lt;/span&gt;&lt;span&gt;Button&lt;/span&gt;&lt;span&gt;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; VideoConversionButton;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This component uses &lt;code&gt;ffmpeg.wasm&lt;/code&gt; to launch an &lt;code&gt;ffmpeg&lt;/code&gt; command. This command takes care of clipping the video to the time limits defined by &lt;code&gt;sliderValues&lt;/code&gt; and converting it to GIF. Note that all these operations are performed client-side in the browser.&lt;/p&gt;
&lt;p&gt;In detail, the &lt;code&gt;ffmpeg&lt;/code&gt; &lt;code&gt;-ss&lt;/code&gt; flag defines the time from which to start reading the video file, while &lt;code&gt;-to&lt;/code&gt; defines the end time. Then, the &lt;code&gt;gif&lt;/code&gt; option specifies that you want to produce a GIF file. Learn more about the flags and options offered by &lt;code&gt;ffmpeg&lt;/code&gt; &lt;a href=&quot;https://www.ffmpeg.org/ffmpeg.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The resulting GIF image is stored in the &lt;code&gt;output.gif&lt;/code&gt; memory file, loaded as a valid &lt;code&gt;&quot;image/gif&quot;&lt;/code&gt; &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Blob&quot;&gt;Blob&lt;/a&gt;, and finally converted to a valid image URL with the &lt;code&gt;[URL.createObjectURL()](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL_static)&lt;/code&gt; native function.&lt;/p&gt;
&lt;h3 id=&quot;putting-it-all-together&quot;&gt;Putting It All Together&lt;/h3&gt;
&lt;p&gt;Now, let’s see the full code of the &lt;code&gt;VideoEditor&lt;/code&gt; component:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// src/components/VideoEditor.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { createFFmpeg } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@ffmpeg/ffmpeg&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { useEffect, useState } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;react&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { Slider, Spin } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;antd&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { VideoPlayer } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./VideoPlayer&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { sliderValueToVideoTime } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;../utils/utils&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; VideoUpload &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./VideoUpload&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; VideoConversionButton &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./VideoConversionButton&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; ffmpeg&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; createFFmpeg&lt;/span&gt;&lt;span&gt;({ log: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt; });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; VideoEditor&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;ffmpegLoaded&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setFFmpegLoaded&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useState&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;videoFile&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setVideoFile&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useState&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;videoPlayerState&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setVideoPlayerState&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useState&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;videoPlayer&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setVideoPlayer&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useState&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;gifUrl&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setGifUrl&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useState&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;sliderValues&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setSliderValues&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useState&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;processing&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setProcessing&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useState&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  useEffect&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // loading ffmpeg on startup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ffmpeg.&lt;/span&gt;&lt;span&gt;load&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      setFFmpegLoaded&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, []);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  useEffect&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; min&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sliderValues[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // when the slider values are updated, updating the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // video time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (min &lt;/span&gt;&lt;span&gt;!==&lt;/span&gt;&lt;span&gt; undefined&lt;/span&gt;&lt;span&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; videoPlayerState &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; videoPlayer) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      videoPlayer.&lt;/span&gt;&lt;span&gt;seek&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sliderValueToVideoTime&lt;/span&gt;&lt;span&gt;(videoPlayerState.duration, min));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, [sliderValues]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  useEffect&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (videoPlayer &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; videoPlayerState) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // allowing users to watch only the portion of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // the video selected by the slider&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;min&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;max&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; sliderValues;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; minTime&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sliderValueToVideoTime&lt;/span&gt;&lt;span&gt;(videoPlayerState.duration, min);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; maxTime&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sliderValueToVideoTime&lt;/span&gt;&lt;span&gt;(videoPlayerState.duration, max);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      if&lt;/span&gt;&lt;span&gt; (videoPlayerState.currentTime &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; minTime) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        videoPlayer.&lt;/span&gt;&lt;span&gt;seek&lt;/span&gt;&lt;span&gt;(minTime);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      if&lt;/span&gt;&lt;span&gt; (videoPlayerState.currentTime &lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; maxTime) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // looping logic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        videoPlayer.&lt;/span&gt;&lt;span&gt;seek&lt;/span&gt;&lt;span&gt;(minTime);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, [videoPlayerState]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  useEffect&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // when the current videoFile is removed,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // restoring the default state&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;videoFile) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      setVideoPlayerState&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      setSliderValues&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      setVideoPlayerState&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      setGifUrl&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, [videoFile]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;Spin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        spinning&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{processing &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; !&lt;/span&gt;&lt;span&gt;ffmpegLoaded}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        tip&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;ffmpegLoaded &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; &apos;Waiting for FFmpeg to load...&apos;&lt;/span&gt;&lt;span&gt; :&lt;/span&gt;&lt;span&gt; &apos;Processing...&apos;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          {videoFile &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &amp;#x3C;&lt;/span&gt;&lt;span&gt;VideoPlayer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;URL&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;createObjectURL&lt;/span&gt;&lt;span&gt;(videoFile)}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              onPlayerChange&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;videoPlayer&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                setVideoPlayer&lt;/span&gt;&lt;span&gt;(videoPlayer);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              onChange&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;videoPlayerState&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                setVideoPlayerState&lt;/span&gt;&lt;span&gt;(videoPlayerState);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          ) &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &amp;#x3C;&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;Upload a video&amp;#x3C;/&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          )}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&apos;upload-div&apos;&lt;/span&gt;&lt;span&gt;}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          &amp;#x3C;&lt;/span&gt;&lt;span&gt;VideoUpload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            disabled&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;!!&lt;/span&gt;&lt;span&gt;videoFile}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onChange&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;videoFile&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              setVideoFile&lt;/span&gt;&lt;span&gt;(videoFile);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&apos;slider-div&apos;&lt;/span&gt;&lt;span&gt;}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          &amp;#x3C;&lt;/span&gt;&lt;span&gt;h3&lt;/span&gt;&lt;span&gt;&gt;Cut Video&amp;#x3C;/&lt;/span&gt;&lt;span&gt;h3&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          &amp;#x3C;&lt;/span&gt;&lt;span&gt;Slider&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            disabled&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;videoPlayerState}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{sliderValues}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            range&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onChange&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;values&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              setSliderValues&lt;/span&gt;&lt;span&gt;(values);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            tooltip&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              formatter: &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&apos;conversion-div&apos;&lt;/span&gt;&lt;span&gt;}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          &amp;#x3C;&lt;/span&gt;&lt;span&gt;VideoConversionButton&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onConversionStart&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              setProcessing&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onConversionEnd&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              setProcessing&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            ffmpeg&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{ffmpeg}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            videoPlayerState&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{videoPlayerState}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            sliderValues&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{sliderValues}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            videoFile&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{videoFile}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onGifCreated&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;girUrl&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              setGifUrl&lt;/span&gt;&lt;span&gt;(girUrl);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        {gifUrl &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&apos;gif-div&apos;&lt;/span&gt;&lt;span&gt;}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &amp;#x3C;&lt;/span&gt;&lt;span&gt;h3&lt;/span&gt;&lt;span&gt;&gt;Resulting GIF&amp;#x3C;/&lt;/span&gt;&lt;span&gt;h3&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &amp;#x3C;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{gifUrl}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&apos;gif&apos;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              alt&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&apos;GIF file generated in the client side&apos;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &amp;#x3C;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              href&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{gifUrl}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              download&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&apos;test.gif&apos;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&apos;ant-btn ant-btn-default&apos;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              Download&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &amp;#x3C;/&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          &amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        )}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span&gt;Spin&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; VideoEditor;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since &lt;code&gt;ffmpeg&lt;/code&gt; takes time to load, you need to let users know that they need to wait a while before they can use the video editor component. Also, &lt;code&gt;ffmpeg&lt;/code&gt; operations take time to execute. This wait logic is implemented by using the Antd Design &lt;code&gt;[Spin](https://ant.design/components/spin/)&lt;/code&gt; component.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://paper-attachments.dropbox.com/s_C8CCC2508B96793E40906CD26AF4C92ACE1FB33CF33FE115E6ACE3BA49F22F52_1663925760548_chrome-capture-2022-8-23.gif&quot; alt=&quot;Preventing users from using the video editor component before ffmpeg is loaded&quot;&gt;&lt;/p&gt;
&lt;p&gt;Also, note that by passing the &lt;code&gt;log: true&lt;/code&gt; option to the &lt;code&gt;createFFmpeg()&lt;/code&gt; function, &lt;code&gt;ffmpeg&lt;/code&gt; will log useful debug info in the console. For example, after &lt;code&gt;ffmpeg&lt;/code&gt; gets loaded, you should be able to see the following lines in the browser console:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[info] use ffmpeg.wasm v0.11.5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;createFFmpeg.js:43 [info] load ffmpeg-core&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;createFFmpeg.js:43 [info] loading ffmpeg-core&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;createFFmpeg.js:43 [info] ffmpeg-core loaded&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What the &lt;code&gt;VideoComponent&lt;/code&gt; does is use all the components presented earlier to allow users to upload a video, select a portion through a slider, convert it to GIF, and download the resulting GIF file.&lt;/p&gt;
&lt;p&gt;Et voilà! You just learned how to build a client-side video editor in React without using any backend functionality!&lt;/p&gt;
&lt;h2 id=&quot;commercial-alternative&quot;&gt;Commercial Alternative&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://img.ly/docs/vesdk/flutter/getting-started/integration/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;VideoEditor SDK&lt;/a&gt; by &lt;a href=&quot;https://img.ly&quot;&gt;IMG.LY&lt;/a&gt; provides powerful video editing features, including cropping and trimming videos in your project. You will receive staples of video editing, including straightening videos, filters, brightness, color adjustments, and more.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Building a client-side video processing and editing application that uses only the browser possible. With WebAssembly, you can run high-performance code written in C or C++ in JavaScript. This allows you to perform complex operations at lightning speed directly in the browser, without having to delegate the work to a server.&lt;/p&gt;
&lt;p&gt;In this tutorial, you learned how to use &lt;code&gt;ffmpeg.wasm&lt;/code&gt; to build a video editor in React. &lt;code&gt;ffmpeg.wasm&lt;/code&gt; is the Wasm port of &lt;code&gt;ffmpeg&lt;/code&gt; and enables video and audio processing and editing directly in the browser. Using it to build a web application to upload a video, cut it, and export it to GIF requires only a few lines of code, and here we have seen how to implement such a video editing application.&lt;/p&gt;
&lt;p&gt;If your app goes beyond merely displaying video, and you want to allow your users to also edit video or create video based templates in the browser, explore our &lt;strong&gt;&lt;a href=&quot;https://img.ly/products/video-sdk/&quot;&gt;VideoEditor SDK&lt;/a&gt;&lt;/strong&gt; for the Web – a performant video editing solution based on WASM and WebCodecs. Try the editor for yourself in action with &lt;a href=&quot;https://img.ly/demos/video-ui/web/&quot;&gt;our showcases&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thanks for reading! Let us know what you think on &lt;a href=&quot;https://twitter.com/imgly&quot;&gt;Twitter&lt;/a&gt;! To stay in the loop, subscribe to our &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;Newsletter&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2023/01/video-editor-ffmpeg-wasm-1.jpg" medium="image"/><category>How-To</category><category>Video Editor</category><category>Web Development</category><category>Web Application</category><category>Video Editing</category><category>Tech</category><category>Tutorial</category></item><item><title>CE.SDK v1.9.0 Release</title><link>https://img.ly/blog/creative-editor-sdk-v_1_9_0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v_1_9_0-release-notes/</guid><description>Get ready to take your creative applications to the next level! This release is packed with exciting new features like video support for web, and more. </description><pubDate>Tue, 13 Dec 2022 08:21:50 GMT</pubDate><content:encoded>&lt;p&gt;We are happy to shine light on more new features since our CE.SDK &lt;a href=&quot;https://img.ly/blog/creative-editor-sdk-v_1_8_0-release-notes/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;v1.8.0&lt;/a&gt; Release. To build powerful features for your application, we are excited to hear your feedback and suggestions.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/cesdk-v-1-9-0-summary.mp4&quot; controls playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;CE.SDK v1.9.0 is out now, and it includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Video Support for Web&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Video Timelines&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Web Audio Support&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Native iOS Platform Support&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Swift Package&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Common Touch Gesture Support&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Apparel UI Showcase&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Spot and Named Colors&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;More Showcases&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;video-support-for-web&quot;&gt;Video Support for Web&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Apply video fills and blocks to your scene!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/Web_Video_Fills_Z1zugux.webp&quot; srcset=&quot;/_astro/Web_Video_Fills_2gNL8I.webp 640w, /_astro/Web_Video_Fills_2qmHEF.webp 750w, /_astro/Web_Video_Fills_JHe8i.webp 828w, /_astro/Web_Video_Fills_8x439.webp 1080w, /_astro/Web_Video_Fills_1O7sFL.webp 1280w, /_astro/Web_Video_Fills_Z1zugux.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We now support adding and editing videos in your web browser. You can apply video fills, add blocks to the scene, and combine any other block to create videos and stories with CE.SDK. For now this feature is only supported in Chromium based browsers.&lt;/p&gt;
&lt;h3 id=&quot;video-timelines&quot;&gt;Video Timelines&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Add, trim and edit your videos in a browser with CE.SDK.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/Video_Timelines_for_Consumer_UIs_and_Studio_UI_1Cs6M.webp&quot; srcset=&quot;/_astro/Video_Timelines_for_Consumer_UIs_and_Studio_UI_ZuBoKr.webp 640w, /_astro/Video_Timelines_for_Consumer_UIs_and_Studio_UI_BKcK7.webp 750w, /_astro/Video_Timelines_for_Consumer_UIs_and_Studio_UI_Z1AaqD2.webp 828w, /_astro/Video_Timelines_for_Consumer_UIs_and_Studio_UI_Z2sJ5Sr.webp 1080w, /_astro/Video_Timelines_for_Consumer_UIs_and_Studio_UI_1jxfvD.webp 1280w, /_astro/Video_Timelines_for_Consumer_UIs_and_Studio_UI_1Cs6M.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Video Timelines and Trimming is coming to our Studio and Design UIs. This adds complete client-side video editing in the browser to our User Interfaces.&lt;/p&gt;
&lt;h3 id=&quot;web-audio-support&quot;&gt;Web Audio Support&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Make it pop! Add your audio to a video.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/Web_Audio_Support_1s4oBD.webp&quot; srcset=&quot;/_astro/Web_Audio_Support_2pzYvf.webp 640w, /_astro/Web_Audio_Support_1zbQaL.webp 750w, /_astro/Web_Audio_Support_2bvbT4.webp 828w, /_astro/Web_Audio_Support_W1gfF.webp 1080w, /_astro/Web_Audio_Support_1cxkqE.webp 1280w, /_astro/Web_Audio_Support_1s4oBD.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In addition to video support, we also introduce a &lt;a href=&quot;https://img.ly/docs/cesdk/js/create-video-c41a08/&quot;&gt;new block type for audio&lt;/a&gt;. You can use audio blocks to add audio files in MP3 and M4a formats to your scene. Like design blocks, you can add and modify them via the Block APIs and attach them to a scene. Note that audio blocks have no visual representation on the canvas, but only in the timeline.&lt;/p&gt;
&lt;p&gt;We dedicate our first implementation to the web. However, native mobile implementations will follow soon.&lt;/p&gt;
&lt;h2 id=&quot;native-ios-support&quot;&gt;Native iOS Support&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/iOS_Native_Support_1PIb9r.webp&quot; srcset=&quot;/_astro/iOS_Native_Support_oKl4b.webp 640w, /_astro/iOS_Native_Support_Z2jjfML.webp 750w, /_astro/iOS_Native_Support_Z1TXgib.webp 828w, /_astro/iOS_Native_Support_hBX2y.webp 1080w, /_astro/iOS_Native_Support_14az60.webp 1280w, /_astro/iOS_Native_Support_1PIb9r.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;With this feature, we support developing native iOS applications with our SDK. It comes with full &lt;strong&gt;Swift API&lt;/strong&gt; support and many integration examples.&lt;/p&gt;
&lt;p&gt;Additionally, CE.SDK v1.9.0 comes with &lt;strong&gt;Common Touch Gesture&lt;/strong&gt; to improve the editing experience on touchpads and mobile devices. That includes gestures like pinch, spread, drag, rotate, tap, and double tap.&lt;/p&gt;
&lt;h2 id=&quot;spot-and-named-colors&quot;&gt;Spot and Named Colors&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Get print-ready with spot and named colors.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/spotnames_bzOWq.webp&quot; srcset=&quot;/_astro/spotnames_Z3Dnrn.webp 640w, /_astro/spotnames_ZuKS6T.webp 750w, /_astro/spotnames_25ootv.webp 828w, /_astro/spotnames_iClG7.webp 1080w, /_astro/spotnames_f6AjL.webp 1280w, /_astro/spotnames_bzOWq.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;With this release we are extending our support for print use cases by adding spot colors which enable the use of custom color mixes in the printing process. Consult the guides on &lt;a href=&quot;https://img.ly/docs/cesdk/js/colors/for-print/spot-c3a150/&quot;&gt;creating spot colors&lt;/a&gt; for more information.&lt;/p&gt;
&lt;h2 id=&quot;more-showcases&quot;&gt;More Showcases&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Explore our showcase site for creative tools perfect for your application.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/showcases_1NUyeG.webp&quot; srcset=&quot;/_astro/showcases_Z2swLUS.webp 640w, /_astro/showcases_2awQdw.webp 750w, /_astro/showcases_Zju000.webp 828w, /_astro/showcases_1UX4Xn.webp 1080w, /_astro/showcases_1RrjB2.webp 1280w, /_astro/showcases_1NUyeG.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;To explore CE.SDK capabilities firsthand, and to look into cases that might be comparable to yours, we provide more showcases on our website.&lt;/p&gt;
&lt;p&gt;Easily build a&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/demos/mobile-ui/web/&quot;&gt;Mobile UI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/demos/photo-ui/web/&quot;&gt;Photo UI&lt;/a&gt; for easy photo editing&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/demos/post-greeting-cards/web/&quot;&gt;Post &amp;#x26; Greeting Card UI&lt;/a&gt; to provide templates and easy adaption for print&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/demos/apparel-ui/web/&quot;&gt;Apparel UI&lt;/a&gt; to let users create fantastic apparel designs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/imgly/cesdk-swift-examples/&quot;&gt;Apparel UI Mobile&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Thanks for reading! Let us know what you think on&lt;/strong&gt; &lt;a href=&quot;https://x.com/imgly&quot;&gt;&lt;strong&gt;Twitter&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;! To stay in the loop, subscribe to our&lt;/strong&gt; &lt;a href=&quot;https://img.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;&lt;strong&gt;Newsletter&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Neslihan</dc:creator><media:content url="https://blog.img.ly/2022/12/creative-editor-sdk-1.png" medium="image"/><category>Release Notes</category><category>Web Application</category><category>Web Development</category><category>Video Editing</category><category>Video Editor</category></item><item><title>How To Build a Video Player in JavaScript</title><link>https://img.ly/blog/how-to-build-video-player-in-javascript/</link><guid isPermaLink="true">https://img.ly/blog/how-to-build-video-player-in-javascript/</guid><description>Create your own JavaScript video player using simple methods for neat results!</description><pubDate>Tue, 27 Sep 2022 17:02:49 GMT</pubDate><content:encoded>&lt;p&gt;Probably a decade ago, it was impossible to play video or audio inside your browser without any third-party services such as Flash or Silverlight. You needed to install a plugin and only play your media while using it, so as you can see, it was very uncomfortable, with low speed and high delays. Nowadays, we have JavaScript with the new version of HTML5. With these new technologies and tools, we can stream our video much quicker, easier, and without any latency. To do it, you will need only a simple &lt;video&gt; tag and give a link to your video stored on your computer. The simple attribute &lt;em&gt;controls&lt;/em&gt; will give you a default video player built into the browser. It’s elementary and doesn’t have many features, so if you want to stream a video on your website in a more professional way using your video player, you’ll need to use JavaScript. And we’ll teach you how to do it in this article!&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;By the end of this guide, you’ll have something similar to this, so if you’re excited, keep reading and follow this tutorial step-by-step!&lt;/p&gt;
&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;html,result&quot; data-slug-hash=&quot;qBYNxxa&quot; data-user=&quot;paulknulst&quot;&gt;&lt;span&gt;See the Pen &lt;a href=&quot;https://codepen.io/paulknulst/pen/qBYNxxa&quot;&gt;How to build a video player in Javascript&lt;/a&gt; by Paul Knulst (&lt;a href=&quot;https://codepen.io/paulknulst&quot;&gt;@paulknulst&lt;/a&gt;) on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;setting-up-the-project&quot;&gt;&lt;strong&gt;Setting Up the Project&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Assuming you are working with UNIX system (or have Git BASH on Windows) you can create all three files that are necessary to build a video player in JavaScript with this command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;mkdir video-player&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cd video-player&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;touch index.html script.js style.css&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To add a simple video player to our application, we have to add the following code to our &lt;code&gt;index.html&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;!DOCTYPE html&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;html lang=&quot;en&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;head&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;meta charset=&quot;UTF-8&quot; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;title&gt;How to build a video player in Javascript&amp;#x3C;/title&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;/head&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;body&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;div class=&quot;player&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &amp;#x3C;video class=&quot;video&quot; controls&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &amp;#x3C;source&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    src=&quot;&amp;#x3C;https://ftp.f1nalboss.de/data/imgly/videoplayer/testvideo.mp4&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    type=&quot;video/mp4&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &amp;#x3C;source&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    src=&quot;&amp;#x3C;https://ftp.f1nalboss.de/data/imgly/videoplayer/testvideo.mp4&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    type=&quot;video/webm&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &amp;#x3C;p&gt;No HTML5 video supported&amp;#x3C;/p&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &amp;#x3C;/video&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;/div&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;script src=&quot;script.js&quot;&gt;&amp;#x3C;/script&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;/body&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;/html&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Within the above code, the &lt;code&gt;&amp;#x3C;video&gt;&lt;/code&gt; element uses a remote video from my FTP. You can either use my default video or add any video from your local computer by adjusting the &lt;code&gt;src&lt;/code&gt; attribute. HTML5 specification supports three different video formats, and the snippet used multiple &lt;code&gt;&amp;#x3C;source&gt;&lt;/code&gt; tags to make the videos available in MP4 and WebM. Furthermore, the &lt;code&gt;&amp;#x3C;p&gt;&lt;/code&gt; tag is used to display pre-defined content to user agents that do not support the &lt;code&gt;video&lt;/code&gt; element.&lt;/p&gt;
&lt;p&gt;The HTML5 &lt;code&gt;&amp;#x3C;video&gt;&lt;/code&gt; tag accepts several native attributes. For example, the &lt;code&gt;controls&lt;/code&gt; attribute displays the standard player controls when added or set to true. You can find out more about &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#attr-controls&quot;&gt;all video attributes here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before continuing, you should apply all styles that are needed within this tutorial by populating your &lt;code&gt;style.css&lt;/code&gt; with all styles &lt;a href=&quot;https://codepen.io/paulknulst/pen/qBYNxxa&quot;&gt;from this CodePen&lt;/a&gt;. Save and open your &lt;code&gt;index.html&lt;/code&gt; and load it within the browser to see the embedded video player as seen below:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;This is what the embedded video player should look like in your index.html file.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 805px) 805px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;805&quot; height=&quot;544&quot; src=&quot;https://img.ly/_astro/build-video-player-with-javascript_cr0hL.webp&quot; srcset=&quot;/_astro/build-video-player-with-javascript_1OPM5z.webp 640w, /_astro/build-video-player-with-javascript_qhdGB.webp 750w, /_astro/build-video-player-with-javascript_cr0hL.webp 805w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;customize-the-video-player-with-javascript&quot;&gt;&lt;strong&gt;Customize the Video Player With JavaScript&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;To customize the video player, you first have to remove the &lt;code&gt;controls&lt;/code&gt; attribute that displays &lt;code&gt;Play&lt;/code&gt;, &lt;code&gt;Pause&lt;/code&gt;, &lt;code&gt;Volume&lt;/code&gt;, etc. because you will implement your own custom controls within this tutorial. Now, check your browser, you will recognize that the controls are gone, and you cannot play the video anymore.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 815px) 815px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;815&quot; height=&quot;540&quot; src=&quot;https://img.ly/_astro/build-video-player-with-javascript_2_Z1embar.webp&quot; srcset=&quot;/_astro/build-video-player-with-javascript_2_w3gnU.webp 640w, /_astro/build-video-player-with-javascript_2_Z1Hc3Vu.webp 750w, /_astro/build-video-player-with-javascript_2_Z1embar.webp 815w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;add-play-and-pause&quot;&gt;&lt;strong&gt;Add Play and Pause&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To enable play and pause the video, you have to add a new button to the &lt;code&gt;index.html&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;div class=&quot;controls&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;button&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            class=&quot;controls__btn playPauseBtn&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            title=&quot;Toggle Play&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        ►&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;/button&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Afterward, open your &lt;code&gt;script.js&lt;/code&gt; and enable functionality by adding this code:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const videoContainer = document.querySelector(&quot;.video-container&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const playPauseBtn = document.querySelector(&quot;.playPauseBtn&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function togglePlay() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if (videoContainer.paused || videoContainer.ended) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    videoContainer.play();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  } else {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    videoContainer.pause();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function updatePlayBtn() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  playPauseBtn.innerHTML = videoContainer.paused ? &quot;►&quot; : &quot;❚❚&quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;playPauseBtn.addEventListener(&quot;click&quot;, togglePlay);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;videoContainer.addEventListener(&quot;click&quot;, togglePlay);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;videoContainer.addEventListener(&quot;play&quot;, updatePlayBtn);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;videoContainer.addEventListener(&quot;pause&quot;, updatePlayBtn);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Within this javascript code, first, the &lt;code&gt;video-container&lt;/code&gt; element and the &lt;code&gt;playPauseBtn&lt;/code&gt; is selected (Line 1 and 2). Then two functions are defined: &lt;code&gt;togglePlay()&lt;/code&gt; and &lt;code&gt;updatePlayBtn()&lt;/code&gt;. &lt;code&gt;togglePlay()&lt;/code&gt; is used to stop and start the video based on its actual state. &lt;code&gt;updatePlayBtn&lt;/code&gt; is used to switch between the Icon which is shown within the video player.&lt;/p&gt;
&lt;p&gt;In the last part of the snippet, a click event listener is added to the &lt;code&gt;playPauseBtn&lt;/code&gt; that executes the &lt;code&gt;togglePlay()&lt;/code&gt; function. Next, three click event listeners are added to the &lt;code&gt;videoContainer&lt;/code&gt; that executes &lt;code&gt;togglePlay()&lt;/code&gt; on mouse click and also executes &lt;code&gt;updatePlayBtn&lt;/code&gt; based on the video’s state.&lt;/p&gt;
&lt;p&gt;Now you can reload your &lt;code&gt;index.html&lt;/code&gt; and should be able to play and pause the video by either clicking the video or the button:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;You can now pause and play your video.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 803px) 803px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;803&quot; height=&quot;526&quot; src=&quot;https://img.ly/_astro/javascript-video-player_VOrAu.webp&quot; srcset=&quot;/_astro/javascript-video-player_1rpo7A.webp 640w, /_astro/javascript-video-player_1oGRhH.webp 750w, /_astro/javascript-video-player_VOrAu.webp 803w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;add-progress-bar&quot;&gt;Add Progress Bar&lt;/h3&gt;
&lt;p&gt;Next, a progress bar will be implemented to show the current timestamp of the video when played. First, add a &lt;code&gt;div&lt;/code&gt; tag to the &lt;code&gt;index.html&lt;/code&gt; which will act as the progress bar:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;div class=&quot;controls&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;div class=&quot;progress&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    	&amp;#x3C;div class=&quot;progress__filled&quot;&gt;&amp;#x3C;/div&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;/div&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // ..&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then open the &lt;code&gt;script.js&lt;/code&gt; and add the following snippet:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const progress = document.querySelector(&quot;.progress&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const progressBar = document.querySelector(&quot;.progress__filled&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function handleProgress() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const progressPercentage = (videoContainer.currentTime / videoContainer.duration) * 100;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  progressBar.style.flexBasis = `${progressPercentage}%`;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function jump(e) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const position = (e.offsetX / progress.offsetWidth) * videoContainer.duration;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  videoContainer.currentTime = position;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;videoContainer.addEventListener(&quot;timeupdate&quot;, handleProgress);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;progress.addEventListener(&quot;click&quot;, jump);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let mousedown = false;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;progress.addEventListener(&quot;mousedown&quot;, () =&gt; (mousedown = true));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;progress.addEventListener(&quot;mousemove&quot;, (e) =&gt; mousedown &amp;#x26;&amp;#x26; jump(e));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;progress.addEventListener(&quot;mouseup&quot;, () =&gt; (mousedown = false));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this snippet, the &lt;code&gt;progress&lt;/code&gt; container and the &lt;code&gt;progress__filled&lt;/code&gt; element will be selected, and two functions will be added: &lt;code&gt;handleProgress()&lt;/code&gt; and &lt;code&gt;jump(e)&lt;/code&gt;. &lt;code&gt;handleProgress()&lt;/code&gt; will be responsible for updating the progress bar. The &lt;code&gt;jump(e)&lt;/code&gt; function is used to enable clicking on the progress bar to jump to the position within the video.&lt;/p&gt;
&lt;p&gt;The last part contains all event listeners that are needed for the progress bar. The &lt;code&gt;handleProgress()&lt;/code&gt; will be called on every &lt;code&gt;timeupdate&lt;/code&gt; event. Also, clicking anywhere on the progress bar will call the &lt;code&gt;jump(e)&lt;/code&gt; method and the video will jump to the position. Additionally, &lt;code&gt;mousedown&lt;/code&gt;, &lt;code&gt;mousemove&lt;/code&gt;, and &lt;code&gt;mouseup&lt;/code&gt; will be used to enable &lt;em&gt;sliding&lt;/em&gt; through the video while holding the mouse button down on the progress bar.&lt;/p&gt;
&lt;h2 id=&quot;closing-notes&quot;&gt;&lt;strong&gt;Closing Notes&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Congratulations! If you followed the tutorial, you learned how to implement your own video player and add custom controls using JavaScript. Now, you can use &lt;a href=&quot;https://codepen.io/paulknulst/pen/qBYNxxa&quot;&gt;my CodePen&lt;/a&gt; and start implementing more controls like &lt;strong&gt;volume control&lt;/strong&gt;, &lt;strong&gt;keyboard shortcuts&lt;/strong&gt;, or &lt;strong&gt;skip controls&lt;/strong&gt; to build your own customized video player.&lt;/p&gt;
&lt;p&gt;If your app goes beyond merely displaying video, and you want to allow your users to also edit video or create video based templates in the browser, check out our &lt;a href=&quot;https://img.ly/products/video-for-web/&quot;&gt;Video Editor for Web&lt;/a&gt;!&lt;/p&gt;</content:encoded><dc:creator>Paul</dc:creator><media:content url="https://blog.img.ly/2022/09/video-player-javascript_tutorial.png" medium="image"/><category>How-To</category><category>Video Editor</category><category>Video Player</category><category>JavaScript</category><category>Web Development</category><category>Web Application</category><category>Tutorial</category></item><item><title>How to Crop and Trim Videos in Flutter</title><link>https://img.ly/blog/how-to-crop-and-trim-videos-in-flutter/</link><guid isPermaLink="true">https://img.ly/blog/how-to-crop-and-trim-videos-in-flutter/</guid><description>Create your own video app in Flutter with the free-to-use and open source solution FFmpeg.</description><pubDate>Tue, 27 Sep 2022 08:45:16 GMT</pubDate><content:encoded>&lt;p&gt;If you are looking for a package that crops and trims videos in Flutter, you must have already come across the &lt;a href=&quot;https://pub.dev/packages/video_trimmer&quot;&gt;video_trimmer&lt;/a&gt; Flutter package. This package can trim videos but does not provide video cropping (at least not out-of-the-box). In fact, none of the packages on pub.dev, as of today, allow cropping a video in Flutter. If you have dug deeper, you might have come across FFmpeg, a powerful video editing command line tool, that is not the easiest to get started with. See the &lt;a href=&quot;https://img.ly/blog/ultimate-guide-to-ffmpeg/&quot;&gt;Ultimate Guide to FFmpeg&lt;/a&gt; for help.In this article we will use the FFmpeg library to crop and trim a video in a Flutter project.&lt;/p&gt;
&lt;p&gt;Here is a list of packages that we will be using; &lt;a href=&quot;https://pub.dev/packages/ffmpeg_kit_flutter&quot;&gt;ffmpeg_kit_flutter&lt;/a&gt; package for cropping and trimming videos, the &lt;a href=&quot;https://pub.dev/packages/path_provider&quot;&gt;path_provider&lt;/a&gt; package to get the path to the application or external directory where the video files will be stored, and the &lt;a href=&quot;https://pub.dev/packages/video_player&quot;&gt;video_player&lt;/a&gt; package to play the video preview.&lt;/p&gt;
&lt;p&gt;This article will not cover building any UI for cropping and trimming. But, it will discuss in brief how to crop the video using the video_trimmer library as well. If you want to package this workflow for production, check out our guide on &lt;a href=&quot;https://img.ly/blog/how-to-run-ffmpeg-inside-a-docker-container/&quot;&gt;running FFmpeg inside a Docker container&lt;/a&gt;. Also, you can try out the code used in this article from this &lt;a href=&quot;https://github.com/numerative/flutter_crop_and_trim_video&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;get-started&quot;&gt;Get Started&lt;/h2&gt;
&lt;p&gt;The end result of this tutorial will be a simple app that would look like the following screenshot.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Create a Flutter app to trim and crop videos easily.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 323px) 323px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;323&quot; height=&quot;700&quot; src=&quot;https://img.ly/_astro/resized_Z1adgTs.webp&quot; srcset=&quot;/_astro/resized_Z1adgTs.webp 323w&quot;&gt;&lt;/p&gt;
&lt;p&gt;When you tap the &lt;strong&gt;Save Video&lt;/strong&gt;, the preview will refresh with the cropped and trimmed video replacing the original video. Follow the instructions in this article, and you will be able to develop a similar Flutter app.&lt;/p&gt;
&lt;p&gt;First, let us start by adding dependencies to a new Flutter project.&lt;/p&gt;
&lt;h3 id=&quot;add-dependencies&quot;&gt;Add Dependencies&lt;/h3&gt;
&lt;p&gt;In your project’s &lt;code&gt;pubspec.yaml&lt;/code&gt; file add the following 3 dependencies.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dependencies&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ffmpeg_kit_flutter&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;^4.5.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  path_provider&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;^2.0.11&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  video_player&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;^2.4.6&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, execute &lt;code&gt;flutter pub get&lt;/code&gt; command from the project folder root.&lt;/p&gt;
&lt;h3 id=&quot;set-minimum-sdk-version-and-platform-version&quot;&gt;Set Minimum SDK Version and Platform Version&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;ffmpeg_kit_flutter&lt;/code&gt; plugin runs on Android SDK API level 24+ and iOS SDK 12.1+. Therefore, modify the module level &lt;code&gt;build.gradle&lt;/code&gt; file to declare the &lt;code&gt;minSdkVersion&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;groovy&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;android {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  defaultConfig {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ..&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    minSdkVersion &lt;/span&gt;&lt;span&gt;24&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ..&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, modify the &lt;code&gt;Podfile&lt;/code&gt; to declare the minimum global platform.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# Uncomment this line to define a global platform for your project&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;platform &lt;/span&gt;&lt;span&gt;:ios&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;12.1&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;add-a-video-asset&quot;&gt;Add a Video Asset&lt;/h3&gt;
&lt;p&gt;For simplicity, we will be using a video asset instead of implementing a file picker. Choose a video file you would like to work with or &lt;a href=&quot;https://github.com/numerative/flutter_crop_and_trim_video/raw/main/assets/file1.mp4&quot;&gt;download&lt;/a&gt; this sample video file. Next, copy the video file to a new directory named &lt;code&gt;assets&lt;/code&gt; at the root of your project folder.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Copy your video of choice to your assets folder at the root of your project folder.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 318px) 318px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;318&quot; height=&quot;240&quot; src=&quot;https://img.ly/_astro/file1-mp4-placement_Z2nfiJa.webp&quot; srcset=&quot;/_astro/file1-mp4-placement_Z2nfiJa.webp 318w&quot;&gt;&lt;/p&gt;
&lt;p&gt;And then reference the video file from the &lt;code&gt;pubspec.yaml&lt;/code&gt; file.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;flutter&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  assets&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    - &lt;/span&gt;&lt;span&gt;assets/file1.mp4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Execute &lt;code&gt;flutter pub get&lt;/code&gt; again.&lt;/p&gt;
&lt;p&gt;Having added the required dependencies, let us move on to coding.&lt;/p&gt;
&lt;h3 id=&quot;implement-video-crop-and-trim&quot;&gt;Implement Video Crop and Trim&lt;/h3&gt;
&lt;p&gt;Replace the code in your &lt;code&gt;main.dart&lt;/code&gt; file with the following code in the code block. This will be our starter code.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;dart&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;package:flutter/material.dart&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; main&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  runApp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; MyApp&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; MyApp&lt;/span&gt;&lt;span&gt; extends&lt;/span&gt;&lt;span&gt; StatelessWidget&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; MyApp&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;span&gt;Key&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; key}) &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; super&lt;/span&gt;&lt;span&gt;(key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; key);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // This widget is the root of your application.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  @override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Widget&lt;/span&gt;&lt;span&gt; build&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BuildContext&lt;/span&gt;&lt;span&gt; context) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; MaterialApp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      title&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &apos;Crop and Trim Demo&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      home&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; MyHomePage&lt;/span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; MyHomePage&lt;/span&gt;&lt;span&gt; extends&lt;/span&gt;&lt;span&gt; StatefulWidget&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; MyHomePage&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;span&gt;Key&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; key}) &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; super&lt;/span&gt;&lt;span&gt;(key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; key);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  @override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  State&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;MyHomePage&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;createState&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; _MyHomePageState&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; _MyHomePageState&lt;/span&gt;&lt;span&gt; extends&lt;/span&gt;&lt;span&gt; State&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;MyHomePage&lt;/span&gt;&lt;span&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  @override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Widget&lt;/span&gt;&lt;span&gt; build&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BuildContext&lt;/span&gt;&lt;span&gt; context) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; Scaffold&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      appBar&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; AppBar&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        title&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Text&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Flutter Crop and Trim&quot;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      body&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Column&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        children&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;initialize-the-input-player&quot;&gt;Initialize the Input Player&lt;/h3&gt;
&lt;p&gt;Add the following code to the &lt;code&gt;_MyHomePageState&lt;/code&gt; class.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;dart&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;dart:io&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;package:flutter/services.dart&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;package:path_provider/path_provider.dart&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;package:video_player/video_player.dart&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; _MyHomePageState&lt;/span&gt;&lt;span&gt; extends&lt;/span&gt;&lt;span&gt; State&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;MyHomePage&lt;/span&gt;&lt;span&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  late&lt;/span&gt;&lt;span&gt; String&lt;/span&gt;&lt;span&gt; inputPath;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  VideoPlayerController&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; controller;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  String&lt;/span&gt;&lt;span&gt; outputPath &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  @override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  void&lt;/span&gt;&lt;span&gt; initState&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    super&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;initState&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    copyVideoToApplicationDirectory&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;((path) &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      inputPath &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; path;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      controller &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; VideoPlayerController&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;file&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;File&lt;/span&gt;&lt;span&gt;(inputPath));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      await&lt;/span&gt;&lt;span&gt; controller&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;initialize&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      await&lt;/span&gt;&lt;span&gt; controller&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;play&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      setState&lt;/span&gt;&lt;span&gt;(() {});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      outputPath &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; getOutputPath&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ///Copy input file to ApplicationStorage Directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ///returns path to copied video&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Future&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;copyVideoToApplicationDirectory&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; filename &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &quot;file1.mp4&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    var&lt;/span&gt;&lt;span&gt; bytes &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; rootBundle.&lt;/span&gt;&lt;span&gt;load&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;assets/file1.mp4&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    String&lt;/span&gt;&lt;span&gt; dir &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; getApplicationDocumentsDirectory&lt;/span&gt;&lt;span&gt;()).path;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    writeToFile&lt;/span&gt;&lt;span&gt;(bytes, &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;dir&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;filename&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; &apos;&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;dir&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;filename&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ///Write to Path.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Future&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;writeToFile&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ByteData&lt;/span&gt;&lt;span&gt; data, &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; path) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    final&lt;/span&gt;&lt;span&gt; buffer &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; data.buffer;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; File&lt;/span&gt;&lt;span&gt;(path).&lt;/span&gt;&lt;span&gt;writeAsBytes&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        buffer.&lt;/span&gt;&lt;span&gt;asUint8List&lt;/span&gt;&lt;span&gt;(data.offsetInBytes, data.lengthInBytes));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;copyVideoToApplicationDirectory&lt;/code&gt; method is copying the video from Assets to the Application directory on the phone’s file system. The resulting path is then stored in the &lt;code&gt;inputPath&lt;/code&gt; variable which is then supplied to the FFmpeg command. For large‑scale workloads, you can move this FFmpeg command to &lt;a href=&quot;https://img.ly/blog/how-to-run-ffmpeg-on-aws-spot-instances-for-scalable-low-cost-video-processing/&quot;&gt;AWS Spot Instances&lt;/a&gt;; our AWS guide shows how to configure a cloud environment for scalable video processing.&lt;/p&gt;
&lt;p&gt;Next, add the &lt;code&gt;VideoPlayer&lt;/code&gt; widget to the &lt;code&gt;Column&lt;/code&gt; widget.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;dart&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Column&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  children&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    (controller &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; null&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        ?&lt;/span&gt;&lt;span&gt; AspectRatio&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        aspectRatio&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; controller&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.value.aspectRatio,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        child&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; VideoPlayer&lt;/span&gt;&lt;span&gt;(controller&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        :&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; SizedBox&lt;/span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run the app and the video should start playing.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;You can now play your video.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 323px) 323px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;323&quot; height=&quot;700&quot; src=&quot;https://img.ly/_astro/resized_screen_ZVo00V.webp&quot; srcset=&quot;/_astro/resized_screen_ZVo00V.webp 323w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In the next step, we will add the FFmpeg command, but before that add the following 2 more methods to the &lt;code&gt;_MyHomePageState&lt;/code&gt; class.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;dart&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;package:ffmpeg_kit_flutter/ffmpeg_kit.dart&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;package:ffmpeg_kit_flutter/log.dart&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;package:ffmpeg_kit_flutter/return_code.dart&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; _MyHomePageState&lt;/span&gt;&lt;span&gt; extends&lt;/span&gt;&lt;span&gt; State&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;MyHomePage&lt;/span&gt;&lt;span&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  /// Output path with a file name where the result will be stored.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Future&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;getOutputPath&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    final&lt;/span&gt;&lt;span&gt; appDirectory &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; Platform&lt;/span&gt;&lt;span&gt;.isAndroid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        ?&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; getExternalStorageDirectory&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        :&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; getApplicationDocumentsDirectory&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    final&lt;/span&gt;&lt;span&gt; externalPath &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;appDirectory&lt;/span&gt;&lt;span&gt;?.&lt;/span&gt;&lt;span&gt;path&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;/out_file.mp4&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; externalPath;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ///Executes the FFMPEG &lt;/span&gt;&lt;span&gt;[command]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ///Note: Green bar on the right is a Flutter issue. &amp;#x3C;https://github.com/flutter/engine/pull/24888&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ///Should get fixed in a 3.1.0+ stable release &amp;#x3C;https://github.com/flutter/engine/pull/24888#issuecomment-1212374010&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Future&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;ffmpegExecute&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; command) &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    final&lt;/span&gt;&lt;span&gt; session &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; FFmpegKit&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;execute&lt;/span&gt;&lt;span&gt;(command);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    final&lt;/span&gt;&lt;span&gt; returnCode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; session.&lt;/span&gt;&lt;span&gt;getReturnCode&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;ReturnCode&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isSuccess&lt;/span&gt;&lt;span&gt;(returnCode)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Success&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      //Replace the preview video&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      await&lt;/span&gt;&lt;span&gt; controller&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;pause&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      await&lt;/span&gt;&lt;span&gt; controller&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;dispose&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      controller &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; VideoPlayerController&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;file&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;File&lt;/span&gt;&lt;span&gt;(outputPath));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      await&lt;/span&gt;&lt;span&gt; controller&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;initialize&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      await&lt;/span&gt;&lt;span&gt; controller&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;play&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      setState&lt;/span&gt;&lt;span&gt;(() {});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    } &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;ReturnCode&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isCancel&lt;/span&gt;&lt;span&gt;(returnCode)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Cancel&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    } &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Error&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      final&lt;/span&gt;&lt;span&gt; failStackTrace &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; session.&lt;/span&gt;&lt;span&gt;getFailStackTrace&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      print&lt;/span&gt;&lt;span&gt;(failStackTrace);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      List&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Log&lt;/span&gt;&lt;span&gt;&gt; logs &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; session.&lt;/span&gt;&lt;span&gt;getLogs&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; element &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; logs) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        print&lt;/span&gt;&lt;span&gt;(element.&lt;/span&gt;&lt;span&gt;getMessage&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;getOutputPath&lt;/code&gt; method provides the path where the resulting video will be saved. The &lt;code&gt;outputPath&lt;/code&gt; will be passed to the FFmpeg command whereas the &lt;code&gt;ffmpegExecute&lt;/code&gt; method is where the FFmpeg magic takes place.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ffmpegExecute&lt;/code&gt; method expects a valid FFmpeg &lt;code&gt;String&lt;/code&gt; command. The &lt;code&gt;String&lt;/code&gt; command is then passed to the &lt;code&gt;FFmpegKit.execute&lt;/code&gt; method which returns an instance of &lt;code&gt;FFMpegSession&lt;/code&gt; . It will tell us whether our command was executed successfully or not. If it was not executed successfully, we can extract error logs from it.&lt;/p&gt;
&lt;h3 id=&quot;ffmpeg-execute-command&quot;&gt;FFmpeg Execute Command&lt;/h3&gt;
&lt;p&gt;Add a &lt;code&gt;TextButton&lt;/code&gt; from where the FFmpeg command shall be sent.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;dart&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;TextButton&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  child&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Text&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Save Video&apos;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  onPressed&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    //TODO: Call FFMPEG Execute&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, call the following &lt;code&gt;ffmpegExecute&lt;/code&gt; method from the &lt;code&gt;onPressed&lt;/code&gt; property.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;dart&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ffmpegExecute&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;-ss 0:00:15 -to 0:00:45 -y -i &lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;inputPath&lt;/span&gt;&lt;span&gt; -filter:v &quot;crop=320:150&quot; -c:a copy &lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;outputPath&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run the app and tap the &lt;strong&gt;Save Video&lt;/strong&gt; button. You will notice that the player is now playing the new cropped and trimmed video.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;You can now play your cropped and trimmed video!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 323px) 323px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;323&quot; height=&quot;700&quot; src=&quot;https://img.ly/_astro/flutter_video_app_crop_trim_screen_18oC7Q.webp&quot; srcset=&quot;/_astro/flutter_video_app_crop_trim_screen_18oC7Q.webp 323w&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you were able to successfully follow the instructions up till here, it is time to dig a little deeper into the FFmpeg command that we just ran earlier.&lt;/p&gt;
&lt;h3 id=&quot;understanding-the-ffmpeg-command&quot;&gt;Understanding the FFmpeg Command&lt;/h3&gt;
&lt;p&gt;Because command FFmpeg is a command line tool, it expects string-only commands. For this reason, we do not have any dart Classes, Methods, or Parameters to work with that we usually get when working with a dart plugin. Let us dissect the above command line command that is helping us crop and trim a video.&lt;/p&gt;





































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Command&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;-ss 0:00:15&lt;/td&gt;&lt;td&gt;Seeks to position on the input video. The trim starts from this position.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-to 0:00:45&lt;/td&gt;&lt;td&gt;Stops reading at the position in the input video. The trim stops at this position. The total length of the video is 0:02:05.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-y&lt;/td&gt;&lt;td&gt;Overwrite output files. Helpful when the Save Video button is tapped more than once.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-i $inputPath&lt;/td&gt;&lt;td&gt;Input file location. This is the file on which the crop and trim are applied.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-filter:v&lt;/td&gt;&lt;td&gt;Apply a filter to the video stream.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;”crop=320:150”&lt;/td&gt;&lt;td&gt;Apply a crop filter from the center of the video that is 320 pixels wide and 150 pixels tall. The original dimensions of the video were 320 x 240.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-c:a copy $outputPath&lt;/td&gt;&lt;td&gt;Specifies the codec with which the output file must be encoded. Here, copy is a special value to indicate the stream is not to be re-encoded. The a after the colon is a stream specifier for the audio stream.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;That will be either the application directory or the external directory of the application, depending on whether the app is running on iOS or Android.&lt;/p&gt;
&lt;p&gt;You can check out the app’s code and play with it by downloading it from this &lt;a href=&quot;https://github.com/numerative/flutter_crop_and_trim_video&quot;&gt;GitHub Repository&lt;/a&gt;. This project allows you to tweak the duration of the trim and dimensions of the crop, so it has more code, but at the heart of it, it still uses the above FFmpeg command.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Download this app code from the GitHub Repository.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 378px) 378px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;378&quot; height=&quot;700&quot; src=&quot;https://img.ly/_astro/flutter_video_app_crop_trim_info_ZDDMgC.webp&quot; srcset=&quot;/_astro/flutter_video_app_crop_trim_info_ZDDMgC.webp 378w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;cropping-using-the-video_trimmer-plugin&quot;&gt;Cropping Using the video_trimmer Plugin&lt;/h2&gt;
&lt;p&gt;As a bonus, here is a tip on how to use the video_trimmer plugin for cropping videos.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://pub.dev/packages/video_trimmer&quot;&gt;video_trimmer&lt;/a&gt; plugin also uses FFmpeg at its core and allows us to pass on an FFmpeg command while saving the video. For this reason, it is an easy task for us to apply the crop to a video using the video_trimmer plugin.&lt;/p&gt;
&lt;p&gt;To do this, pass the following command to the &lt;code&gt;saveTrimmedVideo&lt;/code&gt; method’s &lt;code&gt;ffmpegCommand&lt;/code&gt; parameter as shown in the code block below. The video_trimmer package expects the &lt;code&gt;customVideoFormat&lt;/code&gt; parameter argument when the &lt;code&gt;ffmpegCommand&lt;/code&gt; parameter is used.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;await &lt;/span&gt;&lt;span&gt;_trimmer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    .&lt;/span&gt;&lt;span&gt;saveTrimmedVideo&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        startValue:&lt;/span&gt;&lt;span&gt; _startValue&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        endValue:&lt;/span&gt;&lt;span&gt; _endValue&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        ffmpegCommand:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &apos;-filter:v &quot;crop=320:150&quot;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        customVideoFormat:&lt;/span&gt;&lt;span&gt; &apos;.mp4&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    .&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;((value) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  setState&lt;/span&gt;&lt;span&gt;(() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    _value&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; value;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;limitations-of-this-approach&quot;&gt;Limitations of this Approach&lt;/h2&gt;
&lt;p&gt;The crop that we are applying is from the center of the frame. The present command would also need starting coordinates to crop a non-center frame.&lt;/p&gt;
&lt;p&gt;The project will need a refined UI for cropping and trimming videos to offer a complete app experience to users. The current approach is miles away from creating that experience.&lt;/p&gt;
&lt;p&gt;But perhaps the most significant limitation is FFmpeg’s &lt;strong&gt;licensing&lt;/strong&gt;. FFmpeg is available with both LGPL and GPL licenses, so you must ensure your project is compatible with those licenses. For many commercial projects, this is a non-starter. Alternatively, you can &lt;a href=&quot;https://img.ly/blog/ffmpeg-on-google-cloud-platform-guide/&quot;&gt;run FFmpeg on Google Cloud Platform&lt;/a&gt;; our GCP tutorial walks you through setup.&lt;/p&gt;
&lt;h2 id=&quot;commercial-alternative&quot;&gt;Commercial Alternative&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://img.ly/docs/vesdk/flutter/getting-started/integration/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;VideoEditor SDK (VE.SDK)&lt;/a&gt; from &lt;a href=&quot;https://img.ly&quot;&gt;IMG.LY&lt;/a&gt; provides powerful video editing features, including cropping and trimming videos in a Flutter project. You will receive staples of video editing, including straightening videos, filters, brightness, color adjustments, and more. Follow our guide to learn how to integrate IMG.LY’s &lt;a href=&quot;https://img.ly/blog/a-modern-video-editor-sdk-for-your-flutter-app/&quot;&gt;video editor for Flutter&lt;/a&gt; into your app.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;While still a complex topic, video manipulation is more attainable to implement on Flutter than on native Android. Nevertheless, FFmpeg is the only open-source, free-to-use option to edit videos on Flutter right now. To automate cropping and trimming across many files or build a transcoding server, see our article on &lt;a href=&quot;https://img.ly/blog/building-a-production-ready-batch-video-processing-server-with-ffmpeg/&quot;&gt;building a production‑ready batch video processing server.&lt;/a&gt;&lt;/p&gt;</content:encoded><dc:creator>Michael H.</dc:creator><media:content url="https://blog.img.ly/2022/09/trim_videos_with_flutter_tutorial.png" medium="image"/><category>How-To</category><category>Flutter</category><category>Video Editor</category><category>App Development</category><category>FFmpeg</category><category>Tutorial</category></item><item><title>PE.SDK and VE.SDK 10 for Android and 11 for iOS Release</title><link>https://img.ly/blog/photo-editor-video-editor-sdk-v_10-11-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/photo-editor-video-editor-sdk-v_10-11-release-notes/</guid><description>This major update brings Background Removal and more to PhotoEditor SDK and VideoEditor SDK.</description><pubDate>Wed, 04 May 2022 12:46:21 GMT</pubDate><content:encoded>&lt;p&gt;We are thrilled to announce the release of PhotoEditor SDK and VideoEditor SDK 10 for Android and 11 for iOS. This new major version is packed with features and improvements.&lt;/p&gt;
&lt;p&gt;This release is adding:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Custom Watermarks&lt;/li&gt;
&lt;li&gt;Background Removal for Photos&lt;/li&gt;
&lt;li&gt;Background Removal for Stickers&lt;/li&gt;
&lt;li&gt;Custom Sticker Libraries&lt;/li&gt;
&lt;li&gt;Giphy Integration&lt;/li&gt;
&lt;li&gt;And More Updates for Android and iOS&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;custom-watermarks&quot;&gt;Custom Watermarks&lt;/h2&gt;
&lt;p&gt;With our new support for custom watermarks, you can add your company logo or any other image to photo and video exports. You can place your watermark in either corner or the center of your photo and video. Additionally, you can specify the size of the watermark and determine its distance from the outline if you choose to place it near a corner. Your users will not be able to remove nor modify the watermark.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Set your Custom Watermark for all exports.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 277px) 277px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;277&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/watermark-video-editor-custom-sdk_Z1xbmiB.webp&quot; srcset=&quot;/_astro/watermark-video-editor-custom-sdk_Z1xbmiB.webp 277w&quot;&gt;&lt;/p&gt;
&lt;p&gt;For more details on Custom Watermarks, take a look at our documentation for &lt;a href=&quot;https://img.ly/docs/pesdk/android/customization/watermark/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Android&lt;/a&gt; or &lt;a href=&quot;https://img.ly/docs/pesdk/ios/customization/watermark/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;iOS&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;background-removal-for-photos&quot;&gt;Background Removal for Photos&lt;/h2&gt;
&lt;p&gt;You have unwaveringly requested this feature: we are excited to offer the automatic removal of backgrounds for static content! Background Removal is fully running &lt;strong&gt;on-device&lt;/strong&gt; and currently specializes in images containing a person only. PE.SDK enables this feature exclusively when it detects a person in the photo.&lt;/p&gt;
&lt;p&gt;The removed background will turn transparent if your selected output supports transparency, such as PNG. In other cases, such as JPG, your background removal will be tinted black.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Integrate Background Removal into your application.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 277px) 277px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;277&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/background-removal-photo-editor-app-pe-sdk-1_1hVuOB.webp&quot; srcset=&quot;/_astro/background-removal-photo-editor-app-pe-sdk-1_1hVuOB.webp 277w&quot;&gt;&lt;/p&gt;
&lt;p&gt;This feature is available on Android and iOS 15.0 and higher only. Easily enable Background Removal for Photos with our &lt;a href=&quot;https://img.ly/docs/pesdk/android/features/background_removal/&quot;&gt;Android guide&lt;/a&gt; or &lt;a href=&quot;https://img.ly/docs/pesdk/ios/features/background_removal/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;iOS guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;background-removal-for-stickers&quot;&gt;Background Removal for Stickers&lt;/h2&gt;
&lt;p&gt;A more common use case for automatic background removal is with stickers, so we’ve also added this functionality. Select a sticker including a person and tap the &lt;em&gt;Remove BG&lt;/em&gt; button. Simple!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Let your users create beautiful visuals with Sticker Background Removal.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 277px) 277px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;277&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/background-removal-photo-editor-app-pe-sdk-video_seS2Y.webp&quot; srcset=&quot;/_astro/background-removal-photo-editor-app-pe-sdk-video_seS2Y.webp 277w&quot;&gt;&lt;/p&gt;
&lt;p&gt;This feature is available on Android and iOS 15.0 and higher only. Easily enable Background Removal for Stickers with our &lt;a href=&quot;https://img.ly/docs/vesdk/android/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#background-removal&quot;&gt;Android documentation&lt;/a&gt; or &lt;a href=&quot;https://img.ly/docs/vesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#background-removal&quot;&gt;iOS documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;custom-sticker-libraries&quot;&gt;Custom Sticker Libraries&lt;/h2&gt;
&lt;p&gt;We wanted to make it easier for you to provide your users with more sticker tool content. So far, you were able to create multiple sticker categories with different stickers that could either be part of your app or stored on a server. Additionally, you could &lt;a href=&quot;https://img.ly/docs/pesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#personal-stickers&quot;&gt;enable our personal stickers feature on iOS&lt;/a&gt; or &lt;a href=&quot;https://img.ly/docs/pesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#personal-stickers&quot;&gt;Android&lt;/a&gt;), giving your users the option to select stickers from their camera roll.&lt;/p&gt;
&lt;p&gt;We have now added more ways to provide your users with stickers.&lt;/p&gt;
&lt;h3 id=&quot;android&quot;&gt;Android&lt;/h3&gt;
&lt;p&gt;You can now create sticker categories that do not present our sticker selection interface, but will instead load any arbitrary Fragment. That gives you complete control over the sticker selection screen, and you can use it to load and display any content. When the user selects any of your stickers, all you have to do is pass it back to the SDK with a callback. Get started with your &lt;a href=&quot;https://img.ly/docs/vesdk/android/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#adding-custom-stickers&quot;&gt;Custom Sticker Library with our Android documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;ios&quot;&gt;iOS&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;You can now create sticker categories that do not present our sticker selection interface, but will instead load any arbitrary view controller that conforms to the &lt;code&gt;StickerCollection&lt;/code&gt; protocol. That gives you complete control over the sticker selection screen, and you can use it to load and display any content. When the user selects any of your stickers, simply pass it back to the SDK using a delegate method.&lt;/li&gt;
&lt;li&gt;Additionally, we’ve created a new &lt;code&gt;StickerProviderCategory&lt;/code&gt; that you can pass any object conforming to the &lt;code&gt;StickerProvider&lt;/code&gt; protocol. This category provides most of the features required to interact with sticker content providers, such as search and pagination. You can use this category to very quickly integrate any sticker service.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Find more information on &lt;a href=&quot;https://img.ly/docs/vesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#custom-sticker-view-controller&quot;&gt;Custom Sticker Libraries in the iOS documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;giphy-integration&quot;&gt;GIPHY Integration&lt;/h2&gt;
&lt;p&gt;This online database and search engine for funny GIFs and beautiful animations is a staple in many social applications. Easily integrate GIPHY into your app:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 277px) 277px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;277&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/integrate-giphy-video-editor-photo-sdk_ZWTSEx.webp&quot; srcset=&quot;/_astro/integrate-giphy-video-editor-photo-sdk_ZWTSEx.webp 277w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;android-1&quot;&gt;Android&lt;/h3&gt;
&lt;p&gt;Using our new Custom Sticker Library, we’ve also created an integration for GIPHY on Android. All you have to do is head over to &lt;a href=&quot;https://developers.giphy.com&quot;&gt;GIPHY&lt;/a&gt;, create your API key, pass it to your &lt;code&gt;GiphySettings&lt;/code&gt; and create a &lt;code&gt;GiphyStickerCategoryItem&lt;/code&gt;. Your users will then immediately have access to all the content GIPHY has to offer.&lt;/p&gt;
&lt;p&gt;For more details, visit our &lt;a href=&quot;https://img.ly/docs/vesdk/android/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#adding-giphy&quot;&gt;documentation on adding GIPHY&lt;/a&gt; for Android.&lt;/p&gt;
&lt;h3 id=&quot;ios-1&quot;&gt;iOS&lt;/h3&gt;
&lt;p&gt;Using the new &lt;code&gt;StickerProviderCategory&lt;/code&gt;, we added GIPHY support on iOS. All you have to do is head over to &lt;a href=&quot;https://developers.giphy.com&quot;&gt;GIPHY&lt;/a&gt;, create your API key, and pass this to the GIPHY sticker category. Your users will then immediately have access to all the content GIPHY has to offer.&lt;/p&gt;
&lt;p&gt;For more details, visit our documentation &lt;a href=&quot;https://img.ly/docs/vesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#giphy&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;more-updates-for-android&quot;&gt;More Updates for Android&lt;/h2&gt;
&lt;p&gt;Additionally, we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Increased the minimum API level for PhotoEditor SDK from 16 (Android 4) to 21 (Android 5), which ensures support for 98% of all phones in use.&lt;/li&gt;
&lt;li&gt;Added support for headless video exporting.&lt;/li&gt;
&lt;li&gt;Increased video playback stability.&lt;/li&gt;
&lt;li&gt;Fixed a number of issues with degraded audio quality in videos.&lt;/li&gt;
&lt;li&gt;And added the ability to choose a theme at runtime.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;more-updates-for-ios&quot;&gt;More Updates for iOS&lt;/h2&gt;
&lt;p&gt;Additionally, we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Increased our deployment target from iOS 9 to iOS 13.&lt;/li&gt;
&lt;li&gt;Migrated all usage of OpenGL to Metal.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/vesdk/ios/introduction/migration/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Added a better result API&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/vesdk/ios/introduction/getting_started/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#swiftui&quot;&gt;Added support for SwiftUI&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Enhanced our video export to display a progress indicator and the option to cancel the export.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;thanks-for-reading-let-us-know-what-you-think-on-twitter-or-stay-in-the-loop-with-our-newsletter&quot;&gt;Thanks for reading! Let us know what you think on &lt;a href=&quot;https://twitter.com/imgly&quot;&gt;Twitter&lt;/a&gt;, or stay in the loop with our &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;Newsletter&lt;/a&gt;.&lt;/h3&gt;</content:encoded><dc:creator>Sascha</dc:creator><media:content url="https://blog.img.ly/2022/05/photo-editor-sdk-video-editor-sdk-background-removal.png" medium="image"/><category>Release Notes</category><category>Photo Editor</category><category>Video Editor</category><category>Android App Development</category><category>iOS App Development</category><category>App Development</category></item></channel></rss>