<?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>Learning – IMG.LY Blog</title><description>Posts tagged Learning on the IMG.LY blog.</description><link>https://img.ly/blog/tag/learning/</link><language>en-us</language><image><url>https://img.ly/apple-touch-icon.png</url><title>Learning – IMG.LY Blog</title><link>https://img.ly/blog/tag/learning/</link></image><atom:link href="https://img.ly/blog/tag/learning/rss.xml" rel="self" type="application/rss+xml"/><generator>Astro</generator><lastBuildDate>Tue, 09 Jun 2026 09:48:29 GMT</lastBuildDate><ttl>60</ttl><item><title>How to Build a Short Video Generator Using CE.SDK</title><link>https://img.ly/blog/how-to-build-a-short-video-generator-using-ce-sdk-2/</link><guid isPermaLink="true">https://img.ly/blog/how-to-build-a-short-video-generator-using-ce-sdk-2/</guid><description>Build an AI-powered video generator that creates editable, high-quality videos in the browser—no server-side processing needed.</description><pubDate>Tue, 04 Mar 2025 12:57:47 GMT</pubDate><content:encoded>&lt;p&gt;In the following, I’m presenting a simple cookbook for building an AI-based video generator app, as described in &lt;a href=&quot;https://img.ly/blog/how-to-build-short-video-generator-ai-creative-sdk/&quot;&gt;my previous blog post&lt;/a&gt;. We’re using a combination of different APIs to generate text, audio, and images and will compose &amp;#x26; render the final video using the headless &lt;a href=&quot;https://img.ly/products/creative-sdk&quot;&gt;CreativeEditor SDK&lt;/a&gt;. We also call it the Creative Engine.&lt;/p&gt;
&lt;p&gt;This cookbook showcases the powerful capabilities of our client-side Creative Engine. The engine enables real-time video generation directly in the browser, eliminating the need for server-side processing. What sets this approach apart is its ability to produce editable source files that can then be opened with CreativeEditor SDK.&lt;/p&gt;
&lt;p&gt;This approach is giving users complete control over every aspect of your video–from text and images to animations and overall composition. This means your users can refine and perfect your content even after the initial generation.&lt;/p&gt;
&lt;p&gt;Get the &lt;a href=&quot;https://github.com/imgly/ai-video-creator&quot;&gt;complete code on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;scope&quot;&gt;Scope&lt;/h2&gt;
&lt;p&gt;This tutorial focuses on building an app with a simple UX:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Input your keywords/topics&lt;/li&gt;
&lt;li&gt;Choose between landscape or portrait format&lt;/li&gt;
&lt;li&gt;Generate and preview your video&lt;/li&gt;
&lt;li&gt;Edit the video in the CE.SDK video editor&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The app flow we will create:&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/how-to/er-ai2/workflow.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;The post-editing we will get with CE.SDK:&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/how-to/er-ai2/editing-with-ce-sdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h2 id=&quot;technical-overview&quot;&gt;Technical Overview&lt;/h2&gt;
&lt;p&gt;The app follows three major steps to generate the video.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A script is generated based on User input, the output is a structured XML file.&lt;/li&gt;
&lt;li&gt;The XML script is parsed to extract text and image information. The extracted data will then be used to generate audio &amp;#x26; image files through third-party APIs&lt;/li&gt;
&lt;li&gt;All assets are loaded into the creative engine. This is where the composition, including animation and effects, takes place. The Creative Engine then exports a video and scene file, which can be edited with the Creative Editor.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;
&lt;p&gt;We’ll use a boilerplate with Next.js, React, Typescript &amp;#x26; Tailwind. Make sure you retrieve all necessary keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.anthropic.com/&quot;&gt;Anthropic&lt;/a&gt; (LLM)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://elevenlabs.io/&quot;&gt;ElevenLabs&lt;/a&gt; (text to speech)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fal.ai/&quot;&gt;fal.ai&lt;/a&gt; (text to image)&lt;/li&gt;
&lt;li&gt;IMG.LY CE.SDK – Retrieve a &lt;a href=&quot;https://img.ly/forms/free-trial&quot;&gt;free trial key&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;// Required environment variables&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;NEXT_PUBLIC_ANTHROPIC_API_KEY&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; your_claude_api_key;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;NEXT_PUBLIC_FAL_API_KEY&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; your_fal_ai_key;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;NEXT_PUBLIC_ELEVEN_LABS_KEY&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; your_eleven_labs_key;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;NEXT_PUBLIC_IMG_LY_KEY&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; your_img_ly_key;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;implementation&quot;&gt;Implementation&lt;/h2&gt;
&lt;h3 id=&quot;1-generate-the-script&quot;&gt;1. Generate The Script&lt;/h3&gt;
&lt;p&gt;In this step, we’ll focus on generating the initial prompt and then passing it to the Anthropic API.&lt;/p&gt;
&lt;p&gt;As with many things with LLM, there are many different strategies for structuring the initial prompt. From experience, the best result comes from providing examples of the desired output. We’ve decided to use an XML document; this can be easily parsed later on and is less error-prone compared to a JSON.&lt;/p&gt;
&lt;p&gt;We now define the structure of how information should be saved in the XML.&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;&amp;#x3C;&lt;/span&gt;&lt;span&gt;video&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;group&lt;/span&gt;&lt;span&gt; part&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;intro&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;element&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;text&lt;/span&gt;&lt;span&gt; voiceId&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;50YSQEDPA2vlOxhCseP4&quot;&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;0.2&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        Did you know these fascinating facts about pyramids?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span&gt;text&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;image&lt;/span&gt;&lt;span&gt;&gt;Ancient Egyptian pyramid at sunset&amp;#x3C;/&lt;/span&gt;&lt;span&gt;image&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;element&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;group&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;group&lt;/span&gt;&lt;span&gt; part&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;content&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;element&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;text&lt;/span&gt;&lt;span&gt; voiceId&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;50YSQEDPA2vlOxhCseP4&quot;&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;0.2&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        The Great Pyramid was the tallest structure for over 3,800 years!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span&gt;text&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;image&lt;/span&gt;&lt;span&gt;&gt;Great Pyramid comparison to modern buildings&amp;#x3C;/&lt;/span&gt;&lt;span&gt;image&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;element&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;group&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;group&lt;/span&gt;&lt;span&gt; part&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;outro&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;element&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;text&lt;/span&gt;&lt;span&gt; voiceId&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;50YSQEDPA2vlOxhCseP4&quot;&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;0.4&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        The pyramids continue to reveal their secrets to this day...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span&gt;text&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;image&lt;/span&gt;&lt;span&gt;&gt;A giant 3D question mark hovering over the pyramids&amp;#x3C;/&lt;/span&gt;&lt;span&gt;image&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;element&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;element&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;text&lt;/span&gt;&lt;span&gt; voiceId&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;50YSQEDPA2vlOxhCseP4&quot;&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;0.4&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        Stay curious - there&apos;s always more to discover!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span&gt;text&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;image&lt;/span&gt;&lt;span&gt;&gt;Pyramids under starry night sky&amp;#x3C;/&lt;/span&gt;&lt;span&gt;image&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;element&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;group&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;video&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this tutorial, we’ll focus on the format trivia only as shown in this example. For later iterations, however, I’m planning to implement different content formats (e.g., trivia, quiz, recipe, etc.). Each of these formats will have its example XML. Therefore, I’m nesting the XML in a simple format object to scale this up easily later.&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;interface&lt;/span&gt;&lt;span&gt; Format&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; string&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  example&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; string&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; formats&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Record&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;Format&lt;/span&gt;&lt;span&gt;&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;  trivia: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    name: &lt;/span&gt;&lt;span&gt;&apos;Trivia&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    example: &lt;/span&gt;&lt;span&gt;`&amp;#x3C;video&gt;&amp;#x3C;group&gt;...&amp;#x3C;/group&gt;&amp;#x3C;/video&gt;`&lt;/span&gt;&lt;span&gt; // Add example from above&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;Using this format object with the example, we can now generate the prompt.&lt;/p&gt;
&lt;p&gt;What do we need for this prompt?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Description of the task&lt;/li&gt;
&lt;li&gt;Description of the desired output, incl. an example for the specified format&lt;/li&gt;
&lt;li&gt;Topic as provided by the user&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The topic provided by the user is passed to the function as a string.&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;export&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; createVideoScriptPrompt&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;  topic&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; string&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  formatName&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; string&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &apos;trivia&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&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; format&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; formats[formatName];&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;format) &lt;/span&gt;&lt;span&gt;throw&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`Format ${&lt;/span&gt;&lt;span&gt;formatName&lt;/span&gt;&lt;span&gt;} not found`&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; `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Format: ${&lt;/span&gt;&lt;span&gt;format&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Topic: ${&lt;/span&gt;&lt;span&gt;topic&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;Please write a detailed script for this short video, considering the specified format and topic.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Include an introduction, main content sections, and an outro. Each section should have an image.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Structure the script as an XML Document with clear sections, descriptions for the images.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;The image description should be written as a prompt. This prompt will be used to generate an image.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Put the description between the image tags. The video shouldn&apos;t be longer than 30 seconds.&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;Example format:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;format&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;example&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;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-generate-all-assets&quot;&gt;2. Generate All Assets&lt;/h3&gt;
&lt;p&gt;In the second step, we’ll parse through the LLM response, which should be the XML. We’ll create a simple parsing function to extract all text information that should be sent to text-to-speech and text-to-image AIs.&lt;/p&gt;
&lt;p&gt;Please note that all these steps can be easily streamlined by using AI-assisted coding. Just provide the example XML as input and your desired output.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;API Calls&lt;/strong&gt;&lt;br&gt;
When finding text &amp;#x26; image tags in the XML, we’ll call API functions for text-to-speech and text-to-image. For this example, I’m using ElevenLabs &amp;#x26; fal APIs. You will find all API calls in the api.ts.&lt;/p&gt;
&lt;p&gt;Since the LLM generated a script that includes image prompts, make sure to pass them to the API.&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;export&lt;/span&gt;&lt;span&gt; async&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; generateImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;prompt&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; string&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;string&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;span&gt; null&lt;/span&gt;&lt;span&gt;&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;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Generating image for prompt:&apos;&lt;/span&gt;&lt;span&gt;, prompt);&lt;/span&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; fal.&lt;/span&gt;&lt;span&gt;subscribe&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;fal-ai/flux/dev&apos;&lt;/span&gt;&lt;span&gt;, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      input: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        prompt: prompt,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        size: &lt;/span&gt;&lt;span&gt;&apos;portrait_16_9&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;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; typedResult&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span&gt;as&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;images&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; string&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;&apos;Image generation successful. URL:&apos;&lt;/span&gt;&lt;span&gt;, typedResult.images[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;].url);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; typedResult.images[&lt;/span&gt;&lt;span&gt;0&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;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;Error generating image:&apos;&lt;/span&gt;&lt;span&gt;, error);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&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;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Timestamps&lt;/strong&gt;&lt;br&gt;
Last but not least, we need to come up with timestamps. What’s the duration of each segment? This is critical information for composing the video. Luckily, this is quite easy: Each scene is as long as the generated audio for each segment. This duration for the audio segments can be calculated: Most TTS like ElevenLabs provide timestamps along the audio file. These are typically character-based timestamps, so we first have to calculate the timestamps for each word and then the duration for the entire text section.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ready For The Next Steps&lt;/strong&gt;&lt;br&gt;
All Asset URLs that are generated will be saved in a &lt;code&gt;VideoBlock&lt;/code&gt; object for convenience. The duration of the VideoBlock is the duration of the audio, as calculated above.&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;interface&lt;/span&gt;&lt;span&gt; VideoBlock&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  text&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; string&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  imageUrl&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; string&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;  audioUrl&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; string&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;  startTime&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; number&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  duration&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; number&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  wordTimestamps&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Array&lt;/span&gt;&lt;span&gt;&amp;#x3C;{ &lt;/span&gt;&lt;span&gt;word&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; string&lt;/span&gt;&lt;span&gt;; &lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; number&lt;/span&gt;&lt;span&gt;; &lt;/span&gt;&lt;span&gt;duration&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; number&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;h3 id=&quot;3-generate-the-video&quot;&gt;3. Generate The Video&lt;/h3&gt;
&lt;p&gt;We have everything together now: The completed XML with timestamps, duration, and all assets. It’s now time to generate the video using the creative engine.&lt;/p&gt;
&lt;p&gt;Let’s first add an empty container in our HTML that will be referenced for initiating the creative engine.&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;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  /* Add container for Creative Engine */&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; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;cesdk_container&quot;&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;invisible mt-8 rounded-lg bg-gray-100&quot;&lt;/span&gt;&lt;span&gt; /&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can now initialize the engine. Use &lt;a href=&quot;https://img.ly/docs/cesdk/js/get-started/overview-e18f40/&quot;&gt;this code&lt;/a&gt; snippet from our documentation.&lt;/p&gt;
&lt;p&gt;We’ll then set up a function that creates a simple composition using the provided VideoBlocks. The engine requires you to first create a scene, append a page to the scene, and then create tracks within the page. The tracks are basically the layers in the timeline. I recommend setting one track as a background track using the following snippet:&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;// Set video track as a background track by connecting the page duration to the video 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;setAlwaysOnBottom&lt;/span&gt;&lt;span&gt;(videotrack, &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;engine.block.&lt;/span&gt;&lt;span&gt;setPageDurationSource&lt;/span&gt;&lt;span&gt;(page, videotrack);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Creative Engine provides powerful API calls to style &amp;#x26; manipulate blocks in many ways. Here is an example of how we can animate the images with a slow zoom effect:&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;const&lt;/span&gt;&lt;span&gt; imageZoomAnimation&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;createAnimation&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;crop_zoom&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;setInAnimation&lt;/span&gt;&lt;span&gt;(image, imageZoomAnimation);&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;(imageZoomAnimation, block.duration);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setBool&lt;/span&gt;&lt;span&gt;(imageZoomAnimation, &lt;/span&gt;&lt;span&gt;&apos;animation/crop_zoom/fade&apos;&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Export The Video &amp;#x26; Scene&lt;/strong&gt;&lt;br&gt;
Exporting the video is easy. Just pass the page to the export function. In our example, we’re also saving the scene file so we can edit the video later.&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;// Export video&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; progressCallback&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;  renderedFrames&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; number&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  encodedFrames&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; number&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  totalFrames&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; number&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&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;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`Progress: ${&lt;/span&gt;&lt;span&gt;Math&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;round&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;encodedFrames&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; totalFrames&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;);&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; 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;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  page,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&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;  progressCallback,&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;// Save scene to string&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; sceneData&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; engine.scene.&lt;/span&gt;&lt;span&gt;saveToString&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;// Create scene blob&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; sceneBlob&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Blob&lt;/span&gt;&lt;span&gt;([sceneData], {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  type: &lt;/span&gt;&lt;span&gt;&apos;text/plain&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;4-add-a-video-editor&quot;&gt;4. Add A Video Editor&lt;/h3&gt;
&lt;p&gt;The last step is to add the video editor for post editing and pass the scene file. With CE.SDK, this effort is reduced to adding a few lines of code. In the &lt;code&gt;init&lt;/code&gt; function, we’re configuring the editor and adding callbacks for 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; initEditor&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; 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;A-O53TWXK5bfyconUx7e53S5YU7DzjuGpMAH5vvKjLd0zBa6IhsoF7zChy1uCVbj&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;guides-user&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          theme: &lt;/span&gt;&lt;span&gt;&apos;dark&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          baseURL: &lt;/span&gt;&lt;span&gt;&apos;&amp;#x3C;https://cdn.img.ly/packages/imgly/cesdk-js/1.44.0/assets&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          role: &lt;/span&gt;&lt;span&gt;&apos;Creator&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          ui: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            elements: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              view: &lt;/span&gt;&lt;span&gt;&apos;default&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              panels: {&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;              navigation: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                position: &lt;/span&gt;&lt;span&gt;&apos;top&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                action: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                  save: &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;                  load: &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;                  close: &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;                  download: &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;                  export: &lt;/span&gt;&lt;span&gt;true&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;              dock: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                iconSize: &lt;/span&gt;&lt;span&gt;&apos;normal&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// &apos;large&apos; or &apos;normal&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                hideLabels: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt; // false or true&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;          callbacks: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            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;            onSave&lt;/span&gt;&lt;span&gt;: (&lt;/span&gt;&lt;span&gt;scene&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; string&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; element&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;              const&lt;/span&gt;&lt;span&gt; base64Data&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; btoa&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;unescape&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;encodeURIComponent&lt;/span&gt;&lt;span&gt;(scene)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              element.&lt;/span&gt;&lt;span&gt;setAttribute&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &apos;href&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                `data:application/octet-stream;base64,${&lt;/span&gt;&lt;span&gt;base64Data&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;              element.&lt;/span&gt;&lt;span&gt;setAttribute&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &apos;download&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                `video-${&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; Date&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;toISOString&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;}.scene`&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;              element.style.display &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;none&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              document.body.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(element)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              element.&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;              document.body.&lt;/span&gt;&lt;span&gt;removeChild&lt;/span&gt;&lt;span&gt;(element)&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;            onClose&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;              onClose&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;            onLoad: &lt;/span&gt;&lt;span&gt;&apos;upload&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onDownload: &lt;/span&gt;&lt;span&gt;&apos;download&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onExport: &lt;/span&gt;&lt;span&gt;&apos;download&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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;By following this cookbook, you can streamline the process of AI-generated video creation, making it fast and efficient. This method is especially useful for content creators, educators, and marketers looking to automate video production while maintaining creative control.&lt;br&gt;
Next, try experimenting with video styles, refining AI scripts, or exploring advanced editing.&lt;br&gt;
Feel free to &lt;a href=&quot;https://github.com/imgly/ai-video-creator&quot;&gt;GitHub&lt;/a&gt; repo and share your creations &lt;a href=&quot;https://x.com/imgly&quot;&gt;with us on X&lt;/a&gt;. Happy creating!&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>Eray</dc:creator><media:content url="https://blog.img.ly/2025/03/AI-video-generator-tutorial-1.jpg" medium="image"/><category>AI</category><category>CE.SDK</category><category>How-To</category></item><item><title>CE.SDK v1.44 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v-1-44-0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v-1-44-0-release-notes/</guid><description>Create dynamic content with ease – with multiple clips per track for video editing. Customize your Android Editor with Canvas UI to match your workflow. </description><pubDate>Thu, 06 Feb 2025 07:31:00 GMT</pubDate><content:encoded>&lt;p&gt;Welcome to &lt;strong&gt;CE.SDK v1.44&lt;/strong&gt;! This release brings a range of updates designed to enhance your editing workflow across platforms. Enjoy more vibrant and true-to-life visuals with expanded P3 color support on iOS and Android. On the web, streamline your editing process with the new ability to add multiple clips per track, making timeline management more efficient.&lt;/p&gt;
&lt;p&gt;Let’s dive into the updates!&lt;/p&gt;
&lt;h2 id=&quot;simplify-your-video-editing-workflow&quot;&gt;&lt;strong&gt;Simplify Your Video Editing Workflow&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-44/multiple-clips.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Add &lt;strong&gt;multiple clips to a single track&lt;/strong&gt; on your video timeline! With CE.SDK video editing for the &lt;strong&gt;web&lt;/strong&gt;, you can insert video clips, text, overlays, and more on one track—resulting in a more organized and efficient workspace.&lt;/p&gt;
&lt;p&gt;This update empowers you to create richer, more dynamic sequences while keeping your timeline neat and easy to navigate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Maximize Efficiency&lt;/strong&gt;&lt;br&gt;
Simplicity and speed are key. By reducing the need for multiple tracks, this feature helps users to work smarter and faster—allowing them to focus on creative storytelling and deliver engaging content.&lt;/p&gt;
&lt;p&gt;Get started with our Video Editing for Web &lt;a href=&quot;https://img.ly/docs/cesdk/js/prebuilt-solutions/video-editor-9e533a/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;get-vibrant-colors-with-p3wide-gamut-support&quot;&gt;&lt;strong&gt;Get Vibrant Colors with P3/Wide Gamut Support&lt;/strong&gt;&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/p3-color-support_suVsV.webp&quot; srcset=&quot;/_astro/p3-color-support_2ahnAp.webp 640w, /_astro/p3-color-support_ZeByaQ.webp 750w, /_astro/p3-color-support_2uXPdA.webp 828w, /_astro/p3-color-support_1oTSrF.webp 1080w, /_astro/p3-color-support_VcTWN.webp 1280w, /_astro/p3-color-support_suVsV.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Unlock a broader color range with &lt;strong&gt;P3 color space&lt;/strong&gt; support on &lt;strong&gt;iOS&lt;/strong&gt; and &lt;strong&gt;Android&lt;/strong&gt; devices. This enhancement ensures your designs and content are more vibrant, accurate, and true to life—giving you richer color options for all your projects.&lt;/p&gt;
&lt;p&gt;Set up color spaces with our documentation for &lt;a href=&quot;https://img.ly/docs/cesdk/ios/open-the-editor/uri-resolver-36b624/?language=swift&amp;#x26;platform=ios&amp;#x26;ref=img.ly#editorapicheckp3support/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;iOS&lt;/a&gt; and &lt;a href=&quot;https://img.ly/docs/cesdk/android/open-the-editor/uri-resolver-36b624/?language=kotlin&amp;#x26;platform=android&amp;#x26;ref=img.ly#working-in-different-color-spaceshttps://img.ly/docs/cesdk/engine/api/editor-utils?language=swift&amp;#x26;platform=ios#editorapicheckp3support/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Android&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;tailor-the-android-canvas-menu-to-your-workflows&quot;&gt;Tailor the Android Canvas Menu to Your Workflows&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Customize the Canvas menu in your Android Editor.&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/canvas-menu-android_13989F.webp&quot; srcset=&quot;/_astro/canvas-menu-android_1n3lUT.webp 640w, /_astro/canvas-menu-android_1XULNH.webp 750w, /_astro/canvas-menu-android_1Pdizt.webp 828w, /_astro/canvas-menu-android_13989F.webp 1080w&quot;&gt;&lt;/p&gt;
&lt;p&gt;💡 The Canvas menu appears when you select a design block, letting you edit its settings, like duplicating a selected image.&lt;/p&gt;
&lt;p&gt;Building on mobile configuration introduced in our &lt;a href=&quot;https://img.ly/blog/creative-editor-sdk-v-1-43-0-release-notes/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;last release&lt;/a&gt;, we’ve extended customization to the editor Canvas Menu for Android. This update gives you full control over how the menu and its items appear and behave in the editor:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Customization&lt;/strong&gt;: Configure visibility, transition effects, and decoration. Adjust the style of the divider between buttons.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Item List Control&lt;/strong&gt;: Modify, add, reorder, or hide menu items.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flexible Button and Divider Configuration&lt;/strong&gt;: Adjust button appearance, functionality, and divider styles to match your design requirements.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;More customizations will be available soon, including for iOS.&lt;br&gt;
Explore the &lt;a href=&quot;https://img.ly/docs/cesdk/android/user-interface/customization/canvas-menu-0d2b5b/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;improvements&quot;&gt;Improvements&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Switch the Editor Language without Restarting&lt;/strong&gt;&lt;/p&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/switch-language-sdk_2fgOhx.webp&quot; srcset=&quot;/_astro/switch-language-sdk_1TDR5H.webp 640w, /_astro/switch-language-sdk_ZeLDos.webp 750w, /_astro/switch-language-sdk_1WzYOW.webp 828w, /_astro/switch-language-sdk_ZveCJ9.webp 1080w, /_astro/switch-language-sdk_Z1F4XCL.webp 1280w, /_astro/switch-language-sdk_2fgOhx.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Easily switch languages in our web editor without restarting it. This update lets you update the UI language instantly via API, streamlining localization. Check our &lt;a href=&quot;https://img.ly/docs/cesdk/js/user-interface/localization-508e20/?ref=img.ly#i18n-apihttps://img.ly/docs/cesdk/engine/api/editor-utils?language=kotlin&amp;#x26;platform=android#working-in-different-color-spaceshttps://img.ly/docs/cesdk/engine/api/editor-utils?language=swift&amp;#x26;platform=ios#editorapicheckp3support/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;documentation&lt;/a&gt;, and translate right away!&lt;/p&gt;
&lt;h2 id=&quot;upcoming&quot;&gt;Upcoming&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Record Reactions to Videos on Android&lt;/strong&gt;&lt;br&gt;
We’re excited to announce that Reactions will soon be available on Android. Already live in CE.SDK on iOS, this feature—popularized by platforms like TikTok and Instagram—allows users to capture and share their real-time responses to videos. Enhance engagement and provide content creators with immediate, interactive feedback, making your video content even more dynamic.&lt;/p&gt;
&lt;p&gt;View the &lt;a href=&quot;https://img.ly/docs/cesdk/changelog/#v1440--february-6th-2025&quot;&gt;Changelog&lt;/a&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>Neslihan</dc:creator><media:content url="https://blog.img.ly/2025/02/creative-editor-sdk-1-44.jpg" medium="image"/><category>Release Notes</category><category>CE.SDK</category><category>Creative Editing</category><category>App Development</category><category>Android App Development</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;p&gt;&lt;a href=&quot;https://www.youtube.com/embed/DfQ3fhqfKVc?feature=oembed&quot;&gt;https://www.youtube.com/embed/DfQ3fhqfKVc?feature=oembed&lt;/a&gt;&lt;/p&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 and how to best leverage its capabilities.</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 and unlock its full potential.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Platforms like Instagram, YouTube, and TikTok have revolutionized how we engage with content, setting new standards for consuming video media. With the growing popularity of short-form videos, this trend shows no signs of slowing down.&lt;/p&gt;
&lt;p&gt;Users now not only love to watch videos but also expect intuitive video creation and editing features from modern web applications. Here is why adding a video editor to your Vue.js web application can significantly boost user engagement and satisfaction.&lt;/p&gt;
&lt;p&gt;In this guide, you will discover how to integrate a video editor into a Vue.js project using CreativeEditor SDK (also referred to as &lt;em&gt;CE.SDK&lt;/em&gt;). We will also discuss when this functionality is most beneficial and how to customize the editor for your specific needs.&lt;/p&gt;
&lt;p&gt;For a quick setup, take a look at the &lt;a href=&quot;https://github.com/imgly/cesdk-web-examples/tree/main/integrate-with-vue&quot;&gt;GitHub Vue.js video editor integration&lt;/a&gt; repository to kick off your project.&lt;/p&gt;
&lt;p&gt;Let’s dive in!&lt;/p&gt;
&lt;h2 id=&quot;why-you-should-add-a-video-editor-to-your-vuejs-app&quot;&gt;Why You Should Add a Video Editor to Your Vue.js App?&lt;/h2&gt;
&lt;p&gt;The digital landscape is constantly evolving, but one truth has remained steady: video content continues to dominate.&lt;/p&gt;
&lt;p&gt;Statistics about videos are clear. According to &lt;a href=&quot;https://datareportal.com/reports/digital-2022-instagram-headlines&quot;&gt;Datareportal&lt;/a&gt;, over one-third of all Instagram reels are videos. Similarly, YouTube Shorts garners &lt;a href=&quot;https://blog.youtube/inside-youtube/shorts-revenue-sharing-update/&quot;&gt;over 70 billion daily views&lt;/a&gt;, and TikTok boasts more than &lt;a href=&quot;https://www.statista.com/statistics/272014/global-social-networks-ranked-by-number-of-users/&quot;&gt;1.5 billion monthly active users worldwide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The reasons behind these staggering numbers are two:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Videos are incredibly engaging for audiences.&lt;/li&gt;
&lt;li&gt;Social media platforms have made it remarkably easy to create professional-looking content.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Users now expect to be able to add filters, overlays, audio, music, and text with just a few clicks. As a result, not only do we anticipate video editing features in web applications, but we also demand that these features be simple to use.&lt;/p&gt;
&lt;p&gt;By integrating an intuitive video editor, your Vue.js web app can capitalize on that trend. The goal is to provide a feature that billions of users are already familiar with—and likely expect from your application.&lt;/p&gt;
&lt;p&gt;The payoff? Lowering the barriers to user-generated content, increasing engagement, and driving product distribution!&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;p&gt;In this section, you will learn how to set up a Vue.js video editor using CreativeEditor SDK.&lt;/p&gt;
&lt;h3 id=&quot;requirements&quot;&gt;Requirements&lt;/h3&gt;
&lt;p&gt;Before starting, ensure you have the latest LTS version of Node.js installed on your machine. Otherwise, download and install it from the &lt;a href=&quot;https://nodejs.org/en/download&quot;&gt;official Node.js website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you do not already have a Vue.js project, create a new &lt;a href=&quot;https://vite.dev/&quot;&gt;Vite&lt;/a&gt;-based Vue project by running the following command:&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;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will install and run &lt;a href=&quot;https://github.com/vuejs/create-vue&quot;&gt;create-vue&lt;/a&gt;, the official Vue project scaffolding tool. During the process, you will be prompted to select optional features like TypeScript and testing support. Below is an example of how you can respond to the prompts:&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;√&lt;/span&gt;&lt;span&gt; Project&lt;/span&gt;&lt;span&gt; name:&lt;/span&gt;&lt;span&gt; ...&lt;/span&gt;&lt;span&gt; my-vue-video-editor-app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;√&lt;/span&gt;&lt;span&gt; Add&lt;/span&gt;&lt;span&gt; TypeScript?&lt;/span&gt;&lt;span&gt; ...&lt;/span&gt;&lt;span&gt; No&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; Yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;√&lt;/span&gt;&lt;span&gt; Add&lt;/span&gt;&lt;span&gt; JSX&lt;/span&gt;&lt;span&gt; Support?&lt;/span&gt;&lt;span&gt; ...&lt;/span&gt;&lt;span&gt; No&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; Yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;√&lt;/span&gt;&lt;span&gt; Add&lt;/span&gt;&lt;span&gt; Vue&lt;/span&gt;&lt;span&gt; Router&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; Single&lt;/span&gt;&lt;span&gt; Page&lt;/span&gt;&lt;span&gt; Application&lt;/span&gt;&lt;span&gt; development?&lt;/span&gt;&lt;span&gt; ...&lt;/span&gt;&lt;span&gt; No&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; Yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;√&lt;/span&gt;&lt;span&gt; Add&lt;/span&gt;&lt;span&gt; Pinia&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; state&lt;/span&gt;&lt;span&gt; management?&lt;/span&gt;&lt;span&gt; ...&lt;/span&gt;&lt;span&gt; No&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; Yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;√&lt;/span&gt;&lt;span&gt; Add&lt;/span&gt;&lt;span&gt; Vitest&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; Unit&lt;/span&gt;&lt;span&gt; Testing?&lt;/span&gt;&lt;span&gt; ...&lt;/span&gt;&lt;span&gt; No&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; Yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;√&lt;/span&gt;&lt;span&gt; Add&lt;/span&gt;&lt;span&gt; an&lt;/span&gt;&lt;span&gt; End-to-End&lt;/span&gt;&lt;span&gt; Testing&lt;/span&gt;&lt;span&gt; Solution?&lt;/span&gt;&lt;span&gt; »&lt;/span&gt;&lt;span&gt; No&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;√&lt;/span&gt;&lt;span&gt; Add&lt;/span&gt;&lt;span&gt; ESLint&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; code&lt;/span&gt;&lt;span&gt; quality?&lt;/span&gt;&lt;span&gt; »&lt;/span&gt;&lt;span&gt; Yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;√&lt;/span&gt;&lt;span&gt; Add&lt;/span&gt;&lt;span&gt; Prettier&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; code&lt;/span&gt;&lt;span&gt; formatting?&lt;/span&gt;&lt;span&gt; ...&lt;/span&gt;&lt;span&gt; No&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; Yes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you are unsure about an option, simply select “No” by pressing Enter.&lt;/p&gt;
&lt;p&gt;After the project is set up, navigate to the project folder and install CreativeEditor SDK via &lt;a href=&quot;https://www.npmjs.com/package/@cesdk/cesdk-js&quot;&gt;&lt;code&gt;@cesdk/cesdk-js&lt;/code&gt;&lt;/a&gt; package with this command:&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;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your package.json file will now include the SDK as a dependency:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;@cesdk/cesdk-js&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^1.41.1&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;vue&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^3.5.13&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;vue-router&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^4.4.5&quot;&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;Finally, open your project in a JavaScript IDE, and you are ready to start coding!&lt;/p&gt;
&lt;h3 id=&quot;create-the-video-editor-component&quot;&gt;Create the Video Editor Component&lt;/h3&gt;
&lt;p&gt;In the &lt;code&gt;src/components&lt;/code&gt; folder, create a new file named &lt;code&gt;VideoEditor.vue&lt;/code&gt;. This file will serve as your Vue.js single-file component for the CE.SDK-based video editor.&lt;/p&gt;
&lt;p&gt;In the  like this:&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; CreativeEditorSDK &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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, create your video editor component using the following lines of code:&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;!--&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;components&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;VideoEditor.vue &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;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;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;height: 100vh; width: 100vw&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;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;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import CreativeEditorSDK from &apos;@cesdk/cesdk-js&apos;&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 default {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  props: { config: Object },&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;  _cesdk: &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 class=&quot;line&quot;&gt;&lt;span&gt;  mounted: &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; mounted&lt;/span&gt;&lt;span&gt;() {&lt;/span&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;, &lt;/span&gt;&lt;span&gt;this&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;instance&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;._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;      // customize the editor behavior...&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;  methods: {},&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;  watch: {},&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;  beforeUnmount: &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; beforeDestroy&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // clean up the CE.SDK instance&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;this&lt;/span&gt;&lt;span&gt;._cesdk) {&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; null&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;&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;The component defined above embeds the &lt;code&gt;CreativeEditorSDK&lt;/code&gt; JavaScript element into an HTML &lt;code&gt;&amp;#x3C;div&gt;&lt;/code&gt; container.&lt;/p&gt;
&lt;h3 id=&quot;use-the-component&quot;&gt;Use the Component&lt;/h3&gt;
&lt;p&gt;You can now import the &lt;code&gt;VideoEditor&lt;/code&gt; component in the 
&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; 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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, include it in the &lt;template&gt; section as shown in this snippet:
&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;
&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  :config=&quot;{&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;  }&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;&amp;#x3C;YOUR_LICENSE&gt;&lt;/code&gt; with the license key provided by CreativeEditor SDK and &lt;code&gt;&amp;#x3C;YOUR_USER_ID&gt;&lt;/code&gt; with your user ID to optionally track monthly active users (MAUs) across different devices.&lt;/p&gt;
&lt;p&gt;This setup will launch the video editor with a video preset, enabling users to trim, cut, apply filters, add text overlays, include music, and perform other enhancements to their videos.&lt;/p&gt;
&lt;h2 id=&quot;use-cases-for-the-vuejs-video-editor&quot;&gt;Use Cases for the Vue.js Video Editor&lt;/h2&gt;
&lt;p&gt;Now that you have seen how to build a Vue.js video editor component with a basic CreativeEditor SDK setup, it is time to explore some practical use cases and scenarios.&lt;/p&gt;
&lt;h3 id=&quot;automated-marketing&quot;&gt;Automated Marketing&lt;/h3&gt;
&lt;p&gt;CreativeEditor SDK equips marketers with powerful tools to produce branded videos for multiple campaigns at scale. Key features for this task include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;API Integration&lt;/strong&gt;: Integrate the SDK’s API to automate the creation of videos, reducing manual effort and supporting large-scale video production. This opens the door to automated workflows for marketing campaigns, ad creation, and A/B testing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pre-Designed, Editable Templates&lt;/strong&gt;: Define placeholders, lock or unlock specific design elements, and guide what other users can edit and how. Thanks to this template-based process, it is possible to produce professional assets by leveraging editable &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/web&quot;&gt;video templates&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Template Import from Photoshop:&lt;/strong&gt; Configure the SDK to bulk import .PSD files from Adobe Photoshop, converting them into the CE.SDK scene archive format for streamlined design integration and editing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Manage Branded Assets&lt;/strong&gt;: Build &lt;a href=&quot;https://img.ly/docs/cesdk/vue/import-media/asset-panel/customize-c9a4de/&quot;&gt;custom content libraries&lt;/a&gt; to manage brand assets, including logos, vector graphics, stock photos, and templates.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These capabilities make CE.SDK a reliable technology for scalable, efficient, and brand-consistent video marketing automation.&lt;/p&gt;
&lt;h3 id=&quot;informative-videos-for-e-learning&quot;&gt;Informative Videos for E-Learning&lt;/h3&gt;
&lt;p&gt;CreativeEditor SDK gives educators, teachers, and coaches the tools they need to create impactful and information-rich videos. The entire content creation and editing process requires no advanced technical skills. In detail, users can record, edit, and organize videos across desktop, mobile, or tablet devices.&lt;/p&gt;
&lt;p&gt;Beyond simplifying video production, the SDK is based on reusable templates, so that instructors can quickly adapt materials for various topics while maintaining consistency. Additionally, &lt;a href=&quot;https://img.ly/docs/cesdk/vue/user-interface/ui-extensions-d194d1/&quot;&gt;interactivity plugins&lt;/a&gt;—featuring quizzes, polls, and other learner-focused elements—enhances engagement, making lessons more dynamic and personalized.&lt;/p&gt;
&lt;h3 id=&quot;unique-videos-for-lead-outreach&quot;&gt;Unique Videos for Lead Outreach&lt;/h3&gt;
&lt;p&gt;Cold emails often feel dull and impersonal, frequently ending up in the spam or trash folder. In contrast, personalized video messages are revolutionizing lead outreach.&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK empowers sales, marketing, and business development teams to deliver engaging videos that outshine standard email pitches, offering features such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Customized Video Messages for Leads&lt;/strong&gt;: Craft personalized videos for specific clients or prospects, adding a genuine human touch to your messages. Thanks to &lt;a href=&quot;https://img.ly/docs/cesdk/vue/create-templates/add-dynamic-content/text-variables-7ecb50/&quot;&gt;configurable text variables&lt;/a&gt;, you can customize video content at scale to leave a lasting impression compared to traditional cold emails.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Seamless Integration for Scalable Outreach&lt;/strong&gt;: Produce professional and customized video messages at scale, making it easy for sales teams to personalize outreach without sacrificing efficiency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Translation Capabilities for Global Reach&lt;/strong&gt;: Leverage the SDK’s built-in translation and internationalization features to communicate with audiences worldwide. Adapt your messages to the local customs to convey a truly personalized experience. Test this feature &lt;a href=&quot;https://img.ly/showcases/cesdk/language/web&quot;&gt;in our translation demo&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Take your lead outreach to the next level with these innovative video solutions.&lt;/p&gt;
&lt;h3 id=&quot;social-media-video-content-generation&quot;&gt;Social Media Video Content Generation&lt;/h3&gt;
&lt;p&gt;CE.SDK offers all the tools users need to create captivating videos. It makes it easy to produce shareable content for platforms like Instagram, TikTok, YouTube, LinkedIn, and more.&lt;/p&gt;
&lt;p&gt;Users can take advantage of reusable templates to rapidly bring their ideas to life, without having to start from scratch. They can choose from a variety of pre-designed options, which you can explore in &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/web&quot;&gt;our video editor demo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The support for &lt;a href=&quot;https://img.ly/docs/cesdk/vue/animation/overview-6a2ef2/&quot;&gt;configurable animations&lt;/a&gt; increase engagement and improve the visual appealing. In the SDK, users can also set the mood with music or add narration. Once complete, videos can finally be seamlessly exported in the ideal format and aspect ratio for social media platforms.&lt;/p&gt;
&lt;h3 id=&quot;digital-asset-management&quot;&gt;Digital Asset Management&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://business.adobe.com/blog/basics/digital-asset-management&quot;&gt;Digital Asset Management&lt;/a&gt;, commonly referred to as DAM, is the process of organizing, storing, and managing digital assets—such as videos. Given the large volume of assets companies produce and the way employees and users interact with them, DAM has become a key business process for many organizations.&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK supports DAM by offering an embeddable Vue.js video editor UI component, allowing for centralized video organization, production, repurposing, and editing. This component exposes features like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Asset Libraries&lt;/strong&gt;: CE.SDK can load assets from local files or even integrate third-party libraries via API. Users can search and browse local assets as well as remote images from platforms like Pexels, Unsplash, and Getty within the editor. You can explore our &lt;a href=&quot;https://img.ly/showcases/cesdk?tags=assets&quot;&gt;asset library demo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Permissions for Asset Control&lt;/strong&gt;: Although the SDK does not include role-based permissions out of the box, it connects with backend technologies to manage user access and permissions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extendability for Custom Permissions&lt;/strong&gt;: Developers can extend the SDK to create custom hooks that check permissions and modify the editor’s behavior, ensuring the right users have access to and can edit assets.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These features make CreativeEditor SDK a valuable tool for businesses managing video assets while maintaining brand consistency and workflow efficiency.&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 does not provide a static, pre-configured Vue.js video editor experience. Instead, it supports a large set of customization options to tailor the editor to your specific needs and brand requirements.&lt;/p&gt;
&lt;p&gt;Key customization features include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Build Custom UIs&lt;/strong&gt;: Create fully personalized user interfaces and adapt the editor to your specific use case. This includes repositioning toolbar elements, changing icons, or renaming tools to provide a unique editing experience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feature Activation&lt;/strong&gt;: Enable or disable features based on default settings, giving you control over what is available to users.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internationalization (i18n)&lt;/strong&gt;: Tailor the video editor to different languages and regions. CE.SDK &lt;a href=&quot;https://img.ly/docs/cesdk/vue/user-interface/localization-508e20/&quot;&gt;fully supports i18n&lt;/a&gt;, enabling you to overwrite and extend all text strings in any language.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Media Libraries&lt;/strong&gt;: Define custom, sortable, resource-rich media libraries. CE.SDK supports integration with third-party libraries via API for easy access to external media assets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Single Page Mode&lt;/strong&gt;: Configure the editor to display only one active page at a time for a streamlined experience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Theming&lt;/strong&gt;: Adjust the editor’s theme to align with your app’s design. Choose from built-in themes, generate new ones using the &lt;a href=&quot;https://img.ly/docs/cesdk/vue/user-interface/appearance/theming-4b0938/&quot;&gt;theme generator&lt;/a&gt;, or manually create a custom theme. Test theming in our &lt;a href=&quot;https://img.ly/showcases/cesdk/theming/web&quot;&gt;demo page&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See all of these customizations in action in our &lt;a href=&quot;https://img.ly/showcases/cesdk?tags=customization&quot;&gt;customization demo&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Featuring a Vue.js video editor in your web application can greatly improve the user experience, making it a valuable addition to boosting product success, user reviews, and retention. This is true whether you are building a sales tool, an e-learning platform, or a web app with social media integration.&lt;/p&gt;
&lt;p&gt;With CreativeEditor SDK, you can integrate a fully customizable video editing experience into your Vue.js application in minutes.&lt;/p&gt;
&lt;p&gt;By following the steps outlined in this blog post, you saw how to bring professional-level video editing features to your web users. Explore CE.SDK’s video capabilities and &lt;a href=&quot;https://img.ly/docs/cesdk/vue/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?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=plugins1&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;&lt;/template&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>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 Native into your app and how to best leverage its capabilities.</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;Video content has seen steadily growing demand, especially with the rising popularity of short-form videos. It is no surprise that platforms like YouTube have heavily invested in short-form video content, as video remains a dominant medium for users to create and consume content.&lt;/p&gt;
&lt;p&gt;Platforms like Instagram, TikTok, and YouTube have changed user habits forever. Here is why integrating video creation and editing directly within your web application can dramatically enhance user satisfaction.&lt;/p&gt;
&lt;p&gt;In this guide, you will see how to integrate a video editor into a React app using CreativeEditor SDK (&lt;em&gt;CE.SDK&lt;/em&gt;, for short). We will discuss when it is useful and explain how to customize the editor for your specific use cases.&lt;/p&gt;
&lt;p&gt;For a quick start, check out the &lt;a href=&quot;https://github.com/imgly/cesdk-web-examples/tree/main/integrate-with-react&quot;&gt;GitHub repository&lt;/a&gt; featuring the code for integrating a React video editor.&lt;/p&gt;
&lt;p&gt;Let’s dive in!&lt;/p&gt;
&lt;h2 id=&quot;why-integrate-a-video-editor-in-your-react-web-app&quot;&gt;Why Integrate a Video Editor in Your React Web App?&lt;/h2&gt;
&lt;p&gt;The digital landscape is ever-evolving, but one truth has remained constant for several years: video content reigns supreme.&lt;/p&gt;
&lt;p&gt;The data speaks for itself. Platforms like &lt;a href=&quot;https://newsroom.tiktok.com/en-us/1-billion-people-on-tiktok&quot;&gt;TikTok boast over 1.04 billion monthly active users worldwide&lt;/a&gt;. Similarly, one of most recent &lt;a href=&quot;https://abc.xyz/2024-q1-earnings-call/&quot;&gt;Google’s earnings call&lt;/a&gt; revealed that YouTube Shorts generated approximately 70 billion daily views in just one quarter—a significant leap from 30 billion daily views just two years ago.&lt;/p&gt;
&lt;p&gt;These platforms have set the gold standard by empowering users to create professional-looking videos effortlessly—adding filters, overlays, audio, and text with just a few clicks. This simplicity has made video editing an essential feature across various industries, from social media apps to marketing tools.&lt;/p&gt;
&lt;p&gt;Then, the shift toward shorter, more engaging videos has transformed how users create content and how we consume it. Audiences now demand bite-sized, engaging clips that are easy to produce and share.&lt;/p&gt;
&lt;p&gt;By integrating an easy-to-use video editor, your React web app can tap into this trend. The idea is to offer a feature that billions of users are familiar with—and may already expect from your application.&lt;/p&gt;
&lt;p&gt;The result? Lowering the barrier for user-generated content, boosting engagement, and driving distribution!&lt;/p&gt;
&lt;p&gt;React’s flexibility and component-based architecture make it the perfect match for IMG.LY’s &lt;a href=&quot;https://img.ly/products/creative-sdk&quot;&gt;CreativeEditor SDK&lt;/a&gt;, which guarantees a seamless, high-performance, and feature-rich experience for design, video, and photo editing—all directly in the browser.&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;p&gt;Follow this step-by-step tutorial section and learn how to set up a React video editor in your web app using CreativeEditor SDK. For a different approach, see our guide on &lt;a href=&quot;https://img.ly/blog/how-to-build-a-video-editor-with-wasm-in-react/&quot;&gt;how to build a video editor in React with Wasm&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Integrate CE.SDK in React with the following instructions!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Requirements&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before getting started, make sure you have the latest LTS version of Node.js installed on your machine. Otherwise, &lt;a href=&quot;https://nodejs.org/en/download&quot;&gt;download it from the official website&lt;/a&gt; and install it.&lt;/p&gt;
&lt;p&gt;Next, if you do not already have a React project set up, create a new one using &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-app&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Install CE.SDK via the &lt;a href=&quot;https://www.npmjs.com/package/@cesdk/cesdk-js&quot;&gt;@cesdk/cesdk-js&lt;/a&gt; package with this command:&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;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your &lt;code&gt;package.json&lt;/code&gt; file will now include it as a dependency:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@cesdk/cesdk-js&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^1.41.1&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;react&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^18.3.1&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;react-dom&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^18.3.1&quot;&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;Load your project in a JavaScript IDE, as you are ready to start coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Create the Video Editor Component&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the src folder, create a &lt;code&gt;VideoEditor.jsx&lt;/code&gt; file. This will contain your CE.SDK-based React video editor component.&lt;/p&gt;
&lt;p&gt;Import CreativeEditorSDK from &lt;code&gt;@cesdk/cesdk-js&lt;/code&gt; 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;import&lt;/span&gt;&lt;span&gt; CreativeEditorSDK &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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, initialize your video editor React component with this 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/VideoEditor.jsx&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;@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;import&lt;/span&gt;&lt;span&gt; { useEffect, useRef, 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;// 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;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;  const&lt;/span&gt;&lt;span&gt; cesdk_container&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; useRef&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; [&lt;/span&gt;&lt;span&gt;cesdk&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setCesdk&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;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 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 the CE.SDK container has already been initialized&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;cesdk_container.current) {&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;    let&lt;/span&gt;&lt;span&gt; cleanedUp &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;    // initialize a CE.SDK instance&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    let&lt;/span&gt;&lt;span&gt; instance;&lt;/span&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;(cesdk_container.current, config).&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      async&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;_instance&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;        instance &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;        if&lt;/span&gt;&lt;span&gt; (cleanedUp) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          instance.&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;          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;        // customize the editor behavior...&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;        setCesdk&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&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;    // clean up the CE.SDK instance&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; cleanup&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;      cleanedUp &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;      instance?.&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;      setCesdk&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;
&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; cleanup;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, [cesdk_container]);&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      ref&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{cesdk_container}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{{ width: &lt;/span&gt;&lt;span&gt;&apos;100vw&apos;&lt;/span&gt;&lt;span&gt;, height: &lt;/span&gt;&lt;span&gt;&apos;100vh&apos;&lt;/span&gt;&lt;span&gt; }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&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;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;Replace &lt;code&gt;&amp;#x3C;YOUR_LICENSE&gt;&lt;/code&gt; with the license key you obtain from CreativeEditor SDK and &lt;code&gt;&amp;#x3C;YOUR_USER_ID&gt;&lt;/code&gt; with your user ID to optionally track monthly active users (MAUs) across different devices.&lt;/p&gt;
&lt;p&gt;The component defined above loads the &lt;a href=&quot;https://img.ly/docs/cesdk/js/get-started/overview-e18f40/&quot;&gt;CreativeEditorSDK&lt;/a&gt; JavaScript element into an HTML &lt;/p&gt;&lt;div&gt; element.&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use the Component&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can now import the VideoEditor 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;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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, use it as below:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;#x3C;VideoEditor /&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This will open the video editor with the video preset, allowing users to trim, cut, apply filters, add text overlays, include music, and more to enhance their videos.&lt;/p&gt;
&lt;p&gt;Have a look at our &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/web?ref=img.ly&quot;&gt;interactive demo&lt;/a&gt; to see what the resultant editor should look like.&lt;/p&gt;
&lt;h2 id=&quot;react-video-editor-use-cases&quot;&gt;React Video Editor Use Cases&lt;/h2&gt;
&lt;p&gt;Now that you know how to integrate a React video editor into your web app, you are ready to explore some key use cases. See how the specific features of CreativeEditor SDK can support different scenarios.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Social Media Publishing&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK equips users with the tools they need to create engaging video content. It makes it easier to produce shareable videos for popular social media platforms like Instagram, TikTok, and LinkedIn with features like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reusable Templates&lt;/strong&gt;: Start with video templates downloaded from others or create your own templates and share them with the community. By selecting from a variety of ready-to-use templates for different use cases, users can avoid the blank canvas syndrome and bring their ideas to life quickly. You can explore a range of different templates in our &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/web?template=month-in-review&amp;#x26;ref=img.ly&quot;&gt;video editor demo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Music and Audio Library&lt;/strong&gt;: Users can easily add audio files to their videos, setting the tone through music or narration and creating a captivating atmosphere for their content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Animations&lt;/strong&gt;: The SDK comes with a wide set of &lt;a href=&quot;https://img.ly/docs/cesdk/react/animation/overview-6a2ef2/&quot;&gt;configurable animations&lt;/a&gt; to improve the appearance of design elements within video scenes, significantly boosting engagement.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once a video has been created in your React application, CE.SDK lets users export it in the appropriate formats and aspect ratios for the target social media platforms.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Digital Asset Management&lt;/strong&gt;&lt;/p&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;, refers to the process of organizing, storing, and managing any digital asset—including videos. Over time, DAM has become essential for businesses to maintain efficiency, streamline workflows, and ensure brand consistency across teams.&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK supports DAM by giving your team the ability to organize, edit, and repurpose video content within a centralized, embeddable system. Within the React video editor component, users can easily adapt and edit their assets, ensuring brand consistency while automatically propagating changes across multiple assets.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/web&quot;&gt;Video templates&lt;/a&gt; support placeholders and permissions to guide users’ designs, guaranteeing that all assets stay on-brand. While CE.SDK does not directly support role-based permissions, it can be integrated with any backend technology or framework to control user access.&lt;/p&gt;
&lt;p&gt;Keep in mind that the SDK is also extendable. That way, developers can create custom hooks that check permissions and customize the editor’s behavior accordingly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Marketing Automation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK provides &lt;a href=&quot;https://img.ly/industries/marketing-tech&quot;&gt;marketing tech&lt;/a&gt; to efficiently craft branded, campaign-specific videos at scale.&lt;/p&gt;
&lt;p&gt;Features like pre-designed, editable, and customizable designs help save time in video production and management. Changes to these templates can be automatically propagated, also eliminating the need for manual updates.&lt;/p&gt;
&lt;p&gt;The SDK also supports advanced scenarios like A/B testing, so that your marketing teams can campaign reach by comparing different solutions to see how they perform. Plus, the ability to generate customized videos with &lt;a href=&quot;https://img.ly/docs/cesdk/react/create-templates/add-dynamic-content/text-variables-7ecb50/&quot;&gt;configurable text variables&lt;/a&gt; makes personalizing content easier than ever.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Personalized Videos for Sales Outreach&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We all know how boring and annoying cold emails can be. Marketers and salespeople understand this too, which is why personalized video messages have become the new frontier for pitching.&lt;/p&gt;
&lt;p&gt;Thanks to CreativeEditor SDK, sales teams can easily produce customized videos tailored to specific clients or leads. These videos are far more engaging than standard emails because they feel like a real conversation.&lt;/p&gt;
&lt;p&gt;Also, the translation capabilities offered by the SDK allow sales teams to reach multiple audiences worldwide, breaking down language barriers and personalizing the message for a broader range of targets. Test this feature in our &lt;a href=&quot;https://img.ly/showcases/cesdk/language/web&quot;&gt;translation and internationalization demo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;E-Learning&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK provides educators with the tools they need to create informative videos. Teachers and coaches can quickly produce professional-quality content without requiring extensive technical skills.&lt;/p&gt;
&lt;p&gt;The SDK enhances the learning experience on your React-based e-learning platform through features like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reusability&lt;/strong&gt;: Build a library of templates that can be easily adapted and integrated into existing materials.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy video production&lt;/strong&gt;: Record, edit, and arrange videos directly within the editor, accessible on desktop, mobile, or tablet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plugins for learner interactivity&lt;/strong&gt;: Boost engagement by &lt;a href=&quot;https://img.ly/docs/cesdk/react/user-interface/ui-extensions-d194d1/&quot;&gt;integrating plugins&lt;/a&gt; that add quizzes, polls, and other interactive components within the videos.&lt;/li&gt;
&lt;/ul&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 does not offer a static, pre-configured React video editor experience. Quite the opposite, it presents several customization features to tailor the editor to your specific needs and brand requirements.&lt;/p&gt;
&lt;p&gt;The key customization options are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Build Custom UIs&lt;/strong&gt;: Define fully custom user interfaces adapted to your specific use case.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Theming&lt;/strong&gt;: Adjust the editor’s theme to match your app’s design. Choose from built-in themes, generate new ones using the &lt;a href=&quot;https://img.ly/docs/cesdk/react/user-interface/appearance/theming-4b0938/&quot;&gt;theme generator&lt;/a&gt;, or manually create a custom theme. Test theming in our &lt;a href=&quot;https://img.ly/showcases/cesdk/theming/web&quot;&gt;dedicated demo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Media Libraries&lt;/strong&gt;: Set up customizable, sortable media libraries. CE.SDK supports integration with third-party libraries accessible via API, such as &lt;a href=&quot;https://img.ly/showcases/cesdk/unsplash-image-assets/web&quot;&gt;Unsplash&lt;/a&gt;, allowing you to easily access and use external media assets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Toolbar Customization&lt;/strong&gt;: Reposition toolbar elements, change icons, or rename tools to suit your needs, providing a unique editing experience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internationalization&lt;/strong&gt;: Adapt the video editor component to different languages and regions. CE.SDK offers &lt;a href=&quot;https://img.ly/docs/cesdk/react/user-interface/localization-508e20/&quot;&gt;full i18n support&lt;/a&gt;, enabling you to overwrite and extend all text strings in any language.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Integrating a React video editor into your web app can significantly enhance the user experience and serve as a valuable feature to boost retention, engagement, and potential product distribution. This holds true whether you are building a social media platform, a tool for influencers, a marketing SaaS, or an e-learning system.&lt;/p&gt;
&lt;p&gt;With CreativeEditor SDK, you can quickly add a fully customizable video editing experience to your React application in just minutes.&lt;/p&gt;
&lt;p&gt;By following the steps outlined in this blog post, you can bring professional-level video editing features to your web users. Explore CE.SDK’s video capabilities and &lt;a href=&quot;https://img.ly/docs/cesdk/react/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?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=plugins1&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;&lt;/div&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></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 and how to best leverage its capabilities.</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 and get the most out of it.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;TikTok, Instagram, Facebook, WhatsApp Messenger, YouTube, and X are among the most popular social media platforms. They consistently rank in the top 10 most visited websites and downloaded mobile apps globally. Have you ever asked what is the common thread between them? Video content!&lt;/p&gt;
&lt;p&gt;These platforms have revolutionized how we consume video content. Videos are now shorter, often include subtitles for silent viewing, and are designed to be engaging, professionally produced, and artfully crafted.The challenge lies in meeting user expectations, as modern web applications are now expected to offer intuitive video creation and editing tools. After all, Instagram and TikTok have set the bar quite high when it comes to seamless video production.&lt;/p&gt;
&lt;p&gt;This guide will walk you through implementing a video editor in your Angular web app using CreativeEditor SDK (&lt;em&gt;CE.SDK&lt;/em&gt;). We will also take a look at some scenarios where this video editing is useful and explain how to customize the editor to meet your unique requirements.To jumpstart your project, check out the &lt;a href=&quot;https://github.com/imgly/cesdk-web-examples/tree/main/integrate-with-angular&quot;&gt;GitHub repository for Angular video editor integration&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let’s dive in!&lt;/p&gt;
&lt;h2 id=&quot;why-add-a-video-editor-to-an-angular-application&quot;&gt;Why Add a Video Editor to an Angular Application?&lt;/h2&gt;
&lt;p&gt;Over the past few months, AI has been revolutionizing the tech industry. It all started with AI-generated text and images, but what is next on the horizon? AI-generated videos!&lt;/p&gt;
&lt;p&gt;The appeal is clear—numerous studies show that video is the most engaging medium, resonating deeply with us as humans. This is no surprise, given that &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_most-visited_websites&quot;&gt;YouTube and Instagram rank among the top five most visited websites&lt;/a&gt;, and &lt;a href=&quot;https://www.statista.com/statistics/1285960/top-downloaded-mobile-apps-worldwide/&quot;&gt;TikTok is the most downloaded app worldwide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The problem is that users now demand more than just video content. They expect engaging, professionally edited videos. On top of that, platforms like Instagram and TikTok have raised the bar for intuitive video production and editing. &lt;/p&gt;
&lt;p&gt;As a result, we all expect to be able to add filters, overlays, audio, music, and text to videos with just a few clicks. Meeting these expectations is essential for any application offering video generation features.&lt;/p&gt;
&lt;p&gt;Adding an easy-to-use video editor into your Angular project gives users a powerful tool that they are likely to desire and are already familiar with. That will surely boosts user engagement and help you accelerate the distribution of your online product or service!&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;In this section, you will learn how to integrate an Angular video editor into your wev application through CreativeEditor SDK.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Requirements&lt;/strong&gt;&lt;br&gt;
Before you begin, make sure you have the latest LTS version of Node.js installed on your machine. If that is not your case, download and install it from the &lt;a href=&quot;https://nodejs.org/en/download&quot;&gt;official Node.js website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Next, open your terminal and run the following command to install the &lt;a href=&quot;https://angular.dev/tools/cli&quot;&gt;Angular CLI&lt;/a&gt; globally:&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; -g&lt;/span&gt;&lt;span&gt; @angular/cli&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will make it easy to create and manage Angular projects.&lt;/p&gt;
&lt;p&gt;Once the installation is complete, if you don’t have an Angular project set up, initialize a new Angular project by running:&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;ng&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; my-angular-video-editor-app&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will be prompted with a few questions:&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;Would you like to share pseudonymous usage data about this project with the Angular Team at Google under Google&apos;s Privacy Policy at https://policies.google.com/privacy. For more details and how to change this setting, see https://angular.dev/cli/analytics.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;No&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Global setting: disabled&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Local setting: No local workspace configuration file.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Effective status: disabled&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;✔ Which stylesheet format would you like to use? CSS [ https://developer.mozilla.org/docs/Web/CSS ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;✔ Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? No&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you are unsure, press Enter to accept the default answer.&lt;/p&gt;
&lt;p&gt;After the project is created, navigate to the project folder and install the CreativeEditor SDK (&lt;a href=&quot;https://www.npmjs.com/package/@cesdk/cesdk-js&quot;&gt;@cesdk/cesdk-js&lt;/a&gt;) npm package by running:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;npm install @cesdk/cesdk-js&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Your &lt;strong&gt;package.json&lt;/strong&gt; file will now include the SDK as a dependency:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@angular/animations&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^19.0.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@angular/common&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^19.0.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@angular/compiler&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^19.0.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@angular/core&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^19.0.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@angular/forms&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^19.0.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@angular/platform-browser&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^19.0.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@angular/platform-browser-dynamic&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^19.0.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@angular/router&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^19.0.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@cesdk/cesdk-js&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^1.41.1&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;rxjs&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;~7.8.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;tslib&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^2.3.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;zone.js&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;~0.15.0&quot;&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;Open your project in a JavaScript IDE, as you are ready to start coding!&lt;/p&gt;
&lt;h3 id=&quot;create-a-video-editor-component&quot;&gt;Create a Video Editor Component&lt;/h3&gt;
&lt;p&gt;First, use the Angular CLI to generate the scaffold for your video editor component:&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;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;p&gt;Open the &lt;code&gt;video-editor.component.ts&lt;/code&gt; file inside the &lt;code&gt;src/app/video-editor&lt;/code&gt; folder and initialize your CE.SDK-based Angular video editor 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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { Component, ElementRef, ViewChild } &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;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;  imports: [],&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 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; class&lt;/span&gt;&lt;span&gt; VideoEditorComponent&lt;/span&gt;&lt;span&gt; {&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&gt;&lt;span&gt;&apos;cesdk_container&apos;&lt;/span&gt;&lt;span&gt;) containerRef: ElementRef = {} &lt;/span&gt;&lt;span&gt;as&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;  ngAfterViewInit&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;    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;&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;    CreativeEditorSDK.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.containerRef.nativeElement, config).&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      async&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;instance&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; any&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;        // customize the editor behavior...&lt;/span&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;createDesignScene&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&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 provided by CreativeEditor SDK. Optionally, also set &lt;code&gt;&amp;#x3C;YOUR_USER_ID&gt;&lt;/code&gt; to your user ID to start collecting monthly active user (MAU) data.Then, define video-editor.component.html as below:&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;&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]=&quot;&apos;100&apos;&quot;&lt;/span&gt;&lt;span&gt; [style.width.vw]=&quot;&apos;100&apos;&quot;&gt;&amp;#x3C;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, VideoEditorComponent will be mounted on the above &lt;/p&gt;&lt;div&gt; element.&lt;p&gt;&lt;/p&gt;
&lt;h3 id=&quot;use-the-component&quot;&gt;Use the Component&lt;/h3&gt;
&lt;p&gt;You can now import the component and register it in your &lt;code&gt;app.components.ts&lt;/code&gt; file with these lines of code:&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; { 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; { RouterOutlet } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@angular/router&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;// import the video editor component&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;  imports: [RouterOutlet, VideoEditorComponent], &lt;/span&gt;&lt;span&gt;// register the video editor component&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;span class=&quot;line&quot;&gt;&lt;span&gt;  title&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &apos;my-angular-video-editor-app&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;Next, you can use it in app.component.html with:&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;app-video-editor&gt;&amp;#x3C;/app-video-editor&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This setup will open the video editor with a predefined video template, allowing users to trim, cut, apply filters, add text overlays, insert music, and make other video enhancements.&lt;/p&gt;
&lt;p&gt;Have a look at our &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/web&quot;&gt;interactive demo&lt;/a&gt; to see what the resultant editor should look like.&lt;/p&gt;
&lt;h2 id=&quot;use-cases-the-your-angular-video-editor&quot;&gt;Use Cases the Your Angular Video Editor&lt;/h2&gt;
&lt;p&gt;After learning how to create an Angular video editor component with a basic CreativeEditor SDK integration, it is time to explore some practical use cases in real-world scenarios.&lt;/p&gt;
&lt;h3 id=&quot;video-messages-for-marketing-outreach&quot;&gt;Video Messages for Marketing Outreach&lt;/h3&gt;
&lt;p&gt;Cold emails often come across as generic and impersonal, often ending up in spam or being ignored. In contrast, personalized &lt;a href=&quot;https://www.linkedin.com/pulse/harnessing-power-video-messages-sales-outreach-oliveira-phd--fqrle/&quot;&gt;video messages are transforming marketing outreach&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK enables marketers to create compelling videos that stand out from standard email approaches with capabilities like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Personalized Video Messages for Leads&lt;/strong&gt;: Create tailored videos for individual clients or prospects, adding a personal touch to your marketing outreach efforts and make a stronger impact compared to traditional cold emails.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Global Reach with Translation Features&lt;/strong&gt;: Use the SDK’s built-in translation and internationalization tools to engage with a global audience. Customize messages to fit local cultures and ensure a personalized experience. Try out this feature in our &lt;a href=&quot;https://img.ly/showcases/cesdk/language/web&quot;&gt;translation demo&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;educational-videos-for-e-learning-platforms&quot;&gt;Educational Videos for E-Learning Platforms&lt;/h3&gt;
&lt;p&gt;CreativeEditor SDK offers users in the e-learning industry an intuitive tool to create engaging and educational videos. &lt;/p&gt;
&lt;p&gt;Educators, teachers, and coaches do not need technical skills, as video creation is simple and accessible. Specifically, users can record, edit, and organize videos across desktop, mobile, or tablet browsers with just a few clicks. &lt;/p&gt;
&lt;p&gt;The SDK simplifies content creation through reusable templates. Instructors can integrate their materials into those template to maintain consistency while covering different topics. Finally, support for &lt;a href=&quot;https://img.ly/docs/cesdk/angular/user-interface/ui-extensions-d194d1/&quot;&gt;interactive plugins&lt;/a&gt;—such as quizzes, polls, and other engagement tools—adds a dynamic layer to video lessons.&lt;/p&gt;
&lt;h3 id=&quot;video-content-for-social-media&quot;&gt;Video Content for Social Media&lt;/h3&gt;
&lt;p&gt;CreativeEditor SDK simplifies the process of producing shareable videos for social media sites like Instagram, TikTok, YouTube, but also LinkedIn and others. That is possible thanks to features like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reusable Templates&lt;/strong&gt;: Start with video templates from other creators or design your own and share them with the community. By choosing from a variety of pre-designed templates for different needs, users can avoid the frustration of starting from scratch and bring their ideas to life quickly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Animations&lt;/strong&gt;: Access a broad &lt;a href=&quot;https://img.ly/docs/cesdk/angular/animation/overview-6a2ef2/&quot;&gt;selection of customizable animations&lt;/a&gt; to enhance the visual appeal of video elements, driving higher engagement.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audio Library&lt;/strong&gt;: Effortlessly incorporate audio files into your videos, such as music, voiceovers, or sound effects, to set the mood and create an immersive experience for viewers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once a video is created in Angular application with CE.SDK, users can export it in the ideal formats and aspect ratios for different social media platforms.&lt;/p&gt;
&lt;h3 id=&quot;showcase-products-on-e-commerce-applications&quot;&gt;Showcase Products on E-Commerce Applications&lt;/h3&gt;
&lt;p&gt;Images have long been a simple and effective way to showcase products on e-commerce platforms. Many sites, from eBay to Amazon, have used them for years. At the same time, customer expectations have evolved, and they now seek more engaging ways to visualize products.&lt;/p&gt;
&lt;p&gt;Short, dynamic product videos significantly enhance product presentation. In particular, Amazon data shows that &lt;a href=&quot;https://sellercentral.amazon.com/seller-forums/discussions/t/b031f21d-e8e2-49ea-933c-bef293bf9427&quot;&gt;adding videos can boost sales by up to 9.7%&lt;/a&gt;. It is no surprise that many Amazon sellers have already adopted video to showcase their products.&lt;/p&gt;
&lt;p&gt;With a CE.SDK-based Angular video editor, you can easily create videos that work seamlessly across multiple devices for a unified shopping experience. Thanks to reusable templates, you can customize product videos while maintaining scalability and brand consistency.By leveraging multiple templates and feeding them with diverse data, you can generate automated product video variations at scale.&lt;/p&gt;
&lt;h3 id=&quot;smart-and-automated-workflows&quot;&gt;Smart and Automated Workflows&lt;/h3&gt;
&lt;p&gt;CreativeEditor SDK supports the development of a tool for creating branded videos at scale.&lt;/p&gt;
&lt;p&gt;As it is based on ready-made and editable templates, it simplifies video production and management. The reason is that users can define these templates once through an intuitive point-and-click interface, then effortlessly customize the produced videos via different input resources or &lt;a href=&quot;https://img.ly/docs/cesdk/angular/create-templates/add-dynamic-content/text-variables-7ecb50/&quot;&gt;configurable text variables&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;That automated workflow process boosts productivity and scalability. The SDK also supports advanced features like &lt;a href=&quot;https://www.oracle.com/cx/marketing/what-is-ab-testing/&quot;&gt;A/B testing&lt;/a&gt;. That way, teams can create multiple versions of a campaign video, distribute them on social platforms, and compare their performance.&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 features a versatile Angular video editor experience that can be easily configured and customized to fit your specific requirements and visual preferences.Key customization options supported by CE.SDK include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Feature Activation&lt;/strong&gt;: Enable or disable features as you need, so that you can control the functionality available to users.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom UIs&lt;/strong&gt;: Create fully personalized user interfaces, adapting the editor to your unique use case. This includes repositioning toolbar elements, changing icons, or renaming tools for a tailored editing experience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internationalization&lt;/strong&gt;: Adapt the video editor for different languages and regions. CE.SDK provides &lt;a href=&quot;https://img.ly/docs/cesdk/angular/user-interface/localization-508e20/&quot;&gt;full support for internationalization&lt;/a&gt;, enabling you to customize all text strings in any language.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Export Options&lt;/strong&gt;: Configure which file formats users can select for exporting, along with settings for quality, dimensions, and more.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Role Customization&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 are a set of global settings and scopes. When the role changes, the default settings for that role are applied. You can also use a callback to adjust configurations whenever the role changes and define custom roles to tailor settings for specific user needs or workflows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Media Libraries:&lt;/strong&gt; Create custom, sortable media libraries. CE.SDK supports integration with third-party libraries via API, offering easy access to external media assets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Choose the Start Video:&lt;/strong&gt; Set the editor to display a predefined video at the start, eliminating the blank canvas effect.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Theming&lt;/strong&gt;: Adjust the editor’s theme to match your app’s design. You can select from built-in themes, generate new ones using the &lt;a href=&quot;https://img.ly/docs/cesdk/angular/user-interface/appearance/theming-4b0938/&quot;&gt;theme generator&lt;/a&gt;, or manually create a custom theme. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See all of these customizations in action in our &lt;a href=&quot;https://img.ly/showcases/cesdk?tags=customization&quot;&gt;customization demo&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Adding an video editor to your Angular site or web application greatly enhances user experience. Such a feature drives product success by improving user reviews and increasing retention. Whether you are creating a marketing tool, an e-learning or e-commerce platform, or any web app with social media functionality, a video editor adds immense value.&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK gives you what you need to implement a fully customizable video editing solution into your Angular application in minutes.&lt;/p&gt;
&lt;p&gt;By following the steps in this guide, you learned how to equip your users with a professional and intuitive video editing experience. Explore CE.SDK’s video capabilities and &lt;a href=&quot;https://img.ly/docs/cesdk/angular/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?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=plugins1&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;&lt;/div&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></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_Z17RDlV.webp&quot; srcset=&quot;/_astro/Video-UI_Z1hzsFw.webp 640w, /_astro/Video-UI_ZUG5b8.webp 750w, /_astro/Video-UI_Oc4wg.webp 828w, /_astro/Video-UI_Z17RDlV.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?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=reactnative&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>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 for Flutter into your app and how to best leverage its capabilities.</description><pubDate>Fri, 13 Sep 2024 11:26:15 GMT</pubDate><content:encoded>&lt;p&gt;Video has been the only type of content with steadily growing demand, and it will remain a staple and an expected medium for users to create and consume.&lt;/p&gt;
&lt;p&gt;With platforms such as TikTok, Instagram Reels, and YouTube Shorts dominating and shaping user habits, the ability to create and edit videos directly within your app can significantly increase engagement.&lt;/p&gt;
&lt;p&gt;In this post, we’ll show how to integrate a video editor into a Flutter app using CreativeEditor SDK and customize it for specific use cases, like creating TikTok-style short videos.&lt;/p&gt;
&lt;p&gt;You can check out the code for the default and custom &lt;a href=&quot;https://github.com/imgly/cesdk-flutter-examples/tree/main/showcases/lib/data/code_examples/video&quot;&gt;Flutter video editor on GitHub&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-add-a-video-editor-to-your-flutter-app&quot;&gt;Why add a Video Editor to Your Flutter App?&lt;/h3&gt;
&lt;p&gt;The last decade has made one thing clear: video content is king. Particularly, short-form dominates digital content. At the forefront of this trend are apps like TikTok, which made people more comfortable creating, editing, and sharing bite-sized clips.&lt;/p&gt;
&lt;p&gt;These apps have capitalized on their ability to let users apply filters, and add audio overlays, text, and more, empowering users at all skill levels to make professional-looking videos with minimal effort.&lt;/p&gt;
&lt;p&gt;A host of different use cases stand to profit from this trend by enhancing their user experience with video editing features, particularly marketing tech tooling and apps with a messaging or social media component.&lt;/p&gt;
&lt;p&gt;In general, video creation lowers the threshold for user-generated content and can positively impact distribution and product engagement.&lt;/p&gt;
&lt;p&gt;Flutter, Google’s UI toolkit for building apps across platforms from a single code base, is a perfect fit for &lt;a href=&quot;https://IMG.LY&quot;&gt;IMG.LY&lt;/a&gt;’s Video Editor. What often motivates the choice to use Flutter is that It ensures performance, flexibility, and a seamless user experience on iOS and Android devices. Similarly, our SDK is designed to offer a native cross-platform experience, while relying on the same underlying graphics processing engine, ensuring consistency and interoperability.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;getting-started-integrating-the-video-editor-in-flutter&quot;&gt;Getting Started: Integrating the Video Editor in Flutter&lt;/h3&gt;
&lt;p&gt;Let’s dive into how to set up a video editor in your Flutter app using CreativeEditor SDK.&lt;/p&gt;
&lt;h3 id=&quot;requirements&quot;&gt;Requirements&lt;/h3&gt;
&lt;p&gt;Before we get into the details, here’s what you’ll need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Flutter 3.16.0+&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dart 2.12.0+&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;iOS 16 or later&lt;/strong&gt; (as the video editor is currently only available for iOS, Android coming soon)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Swift 5.10 and Xcode 15.4&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First, ensure your &lt;code&gt;pubspec.yml&lt;/code&gt; file includes the necessary 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;  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.34.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once your environment is set up, you’re ready to start coding.&lt;/p&gt;
&lt;h3 id=&quot;setting-up-the-editor&quot;&gt;Setting Up the Editor&lt;/h3&gt;
&lt;p&gt;After adding the &lt;code&gt;imgly_editor&lt;/code&gt; dependency, import the package in your 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; &quot;package:imgly_editor/imgly_editor.dart&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next step is to initialize the editor by providing an instance of &lt;code&gt;EditorSettings&lt;/code&gt;. This setup requires a license key, which you can obtain from CreativeEditor SDK, and an optional &lt;code&gt;userId&lt;/code&gt; that helps track monthly active users (MAUs) across different devices.&lt;/p&gt;
&lt;p&gt;Here’s a basic example of how to open the video editor:&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;  /// Opens the editor.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  void&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; &quot;YOUR_LICENSE&quot;&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; &quot;YOUR_USER_ID&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;		/// Open the editor and retrieve the editing result.&lt;/span&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; preset,&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&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 video preset, enabling users to trim, cut, and add filters, text overlays, music, and more to their videos.&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_Z1vXnTi.webp&quot; srcset=&quot;/_astro/flutter-video-editor_mCglm.webp 640w, /_astro/flutter-video-editor_bQizb.webp 750w, /_astro/flutter-video-editor_Z1vXnTi.webp 814w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;use-cases-building-a-tiktok-like-experience&quot;&gt;Use Cases: Building a TikTok-Like Experience&lt;/h3&gt;
&lt;p&gt;Now that we have integrated the basic editor configuration into your Flutter app, let’s revisit some prominent 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 a short-form video, TikTok-like user experience, the most important factor is the ease of use of any video editor and content such as stickers or audio overlays.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The following SDK capabilities can help you achieve that goal:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Control Video Duration and Position in Time&lt;/strong&gt;: Users should be able to trim video clips on a timeline and position them relative to other tracks, such as audio clips.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filters &amp;#x26; Effects&lt;/strong&gt;: Filters are essential for setting the tone of the video. Whether users want a retro, high contrast, or soft pastel look, filters provide creative control over the visual style.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Text &amp;#x26; Stickers&lt;/strong&gt;: Allow users to add text captions—especially important for content often watched on mute. Stickers and emojis can add a playful element to videos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Music &amp;#x26; Audio&lt;/strong&gt;: Like TikTok, you can allow users to add background music or sound effects. Providing a library of popular tracks or sound snippets can enhance the content creation experience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Video Templates&lt;/strong&gt;: Give your users a head start with customizable video templates for different themes, topics, and occasions. &lt;a href=&quot;https://IMG.LY&quot;&gt;IMG.LY&lt;/a&gt;’s CE.SDK comes with a web video editor to help build and deliver these templates to your Flutter app. You can explore a range of different templates in our &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/web?template=month-in-review&quot;&gt;video editor demo&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By integrating these features, you’ll empower users to create engaging, shareable content, elevating your app’s video creation experience to the level of consumer-grade social media apps.&lt;/p&gt;
&lt;h3 id=&quot;influencers-and-marketing&quot;&gt;Influencers and Marketing&lt;/h3&gt;
&lt;p&gt;If your app is targeting influencers or businesses, the ability to quickly create branded video content is key. You can offer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Branded Templates&lt;/strong&gt;: Pre-made templates that align with a brand’s style, allowing users to easily drop in their video footage and text while maintaining brand consistency. Again, check out the web editor demo to see how to build &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/web?template=month-in-review&quot;&gt;video templates&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Watermarks&lt;/strong&gt;: Adding a watermark or logo as a brand signifier to videos can help with brand visibility and make sure content always points back to the creator.&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;ecommerce-and-user-generated-content&quot;&gt;eCommerce and User-Generated Content&lt;/h3&gt;
&lt;p&gt;Video is a powerful medium to showcase products, especially on marketplaces that can leverage user-generated content and enable vendors as well as customers to create product or review videos.&lt;/p&gt;
&lt;p&gt;For example, users could create unboxing videos, product reviews, or tutorials using the same trimming, filter, and music tools offered in a TikTok-style editor. These videos can then be shared on social media or used within the app to enhance the shopping experience.&lt;/p&gt;
&lt;p&gt;Likewise, showcasing products using authentic demo videos tap into familiar patterns of video consumption and can boost sales for vendors.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;customization-options-with-creativeeditor-sdk&quot;&gt;Customization Options with CreativeEditor SDK&lt;/h3&gt;
&lt;p&gt;We have designed the Flutter plugin to be adaptable to match your brand and use case-specific requirements. Soon the plugin will also support more advanced customization options such as the ability to &lt;strong&gt;activate or deactivate features by default.&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;UI Customization&lt;/strong&gt;: Modify the look and feel of the editor to match your app’s branding. We provide options for &lt;strong&gt;theming&lt;/strong&gt;, &lt;strong&gt;styling color palettes&lt;/strong&gt;, and &lt;strong&gt;callbacks&lt;/strong&gt; to hook into editor events.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Video Presets&lt;/strong&gt;: You can create custom video presets based on your users’ needs. For instance, you may want to limit video length or optimize for certain resolutions, depending on the target platform.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Video Templates&lt;/strong&gt;: You can use the CE.SDK web UI to generate any number of video templates including collages, text designs, and animations to give your users professional-looking starting points for their video designs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Assets&lt;/strong&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;hr&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Integrating a video editor into your Flutter app will 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. 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 outlined in this post, you can bring professional-level video editing features to your users. 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?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=plugins1&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&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/09/how-to-flutter-photo-video-design-editor-sdk.png" medium="image"/><category>Video Editing</category><category>Flutter</category><category>Tutorial</category><category>Learning</category></item><item><title>CE.SDK v1.33 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v-1-33-0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v-1-33-0-release-notes/</guid><description>Explore new mobile design and photo editor configurations, plugins for UI customization, voiceover capabilities, and more.</description><pubDate>Thu, 29 Aug 2024 12:08:57 GMT</pubDate><content:encoded>&lt;p&gt;Welcome to the latest update of CE.SDK! We are bringing you new features that enhance your app’s creative capabilities and user experience. This release includes Configurations for a Design Editor or Photo Editor on iOS and Android, Plugins, Voiceover Capabilities, and more.&lt;/p&gt;
&lt;p&gt;With this release, you can:&lt;/p&gt;
&lt;h2 id=&quot;integrate-a-design-editor-on-ios-and-android&quot;&gt;Integrate a Design Editor on iOS and Android&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-33/page-management-cesdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Get started with our new Design Editor configuration for iOS and Android. The out-of-the-box package is designed for easy creation and management of multipage designs.&lt;/p&gt;
&lt;p&gt;Users can switch between editing and the page overview mode to review and adjust their work.&lt;/p&gt;
&lt;p&gt;Keep the design process straightforward and efficient: the editor features a dock at the bottom, offering convenient access to essential tools like adding text, images, stickers, and uploading new assets. Additionally, you can insert a photo directly from your camera.&lt;/p&gt;
&lt;h3 id=&quot;key-features&quot;&gt;&lt;strong&gt;Key Features&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Page Management&lt;/strong&gt;&lt;br&gt;
Create and manage your design pages within a template. It’s easy to create fun carousel posts, as seen on Instagram and LinkedIn, or create a series. Head to the ‘Pages’ icon on the top right bar. In the page overview, you can create, duplicate, and edit a page. Lastly, you can change the order of pages by moving them up and down.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Image Settings&lt;/strong&gt;&lt;br&gt;
Selecting an image lets you fine-tune adjustment settings, and add filters, effects, or blur. Easily crop, straighten, rotate, or flip images.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://apps.apple.com/us/app/img-ly-design-editor/id1672991141&quot;&gt;Try the Design Editor Configuration on iOS&lt;/a&gt; and &lt;a href=&quot;https://play.google.com/store/apps/details?id=ly.img.cesdk.catalog&amp;#x26;pli=1&quot;&gt;Android&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;use-plugins-to-customize-ui-and-add-quick-actions&quot;&gt;Use Plugins to Customize UI and Add Quick Actions&lt;/h2&gt;
&lt;p&gt;We’re excited to introduce the first part of our plugin release for CE.SDK on the web: with this release, you can tailor the editor’s UI elements, reorder components, and add quick actions like &lt;strong&gt;background removal.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;grafik.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1886px) 1886px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1886&quot; height=&quot;1289&quot; src=&quot;https://img.ly/_astro/plugins-customize-UI_Z1V1dcA.webp&quot; srcset=&quot;/_astro/plugins-customize-UI_Z1VSlKa.webp 640w, /_astro/plugins-customize-UI_1qIha2.webp 750w, /_astro/plugins-customize-UI_XGkYN.webp 828w, /_astro/plugins-customize-UI_ZBDlJC.webp 1080w, /_astro/plugins-customize-UI_Z1fvfbb.webp 1280w, /_astro/plugins-customize-UI_Z1uBYIU.webp 1668w, /_astro/plugins-customize-UI_Z1V1dcA.webp 1886w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We’ve enabled extension points within key areas of the UI: the Canvas, Navigation bar, Inspector Bar, Dock, and Canvas Menu. Modify the appearance of existing features, register new components, and integrate quick actions. For example, you can add a “Background Removal” button directly in the Canvas Menu or create complex interactions like custom cut-out lines.&lt;/p&gt;
&lt;p&gt;For more details on this first batch release and the upcoming plugins, please read our dedicated &lt;a href=&quot;https://img.ly/blog/plugin-release-part-1-customizing-the-ui-quick-actions/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;article&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;add-voiceovers-to-videos-on-ios&quot;&gt;Add Voiceovers to Videos on iOS&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-33/voice-over.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Add voiceover tracks directly within your mobile app, making your projects more dynamic and engaging. Whether creating a tutorial, narrating a slideshow, or adding commentary to a video, this feature allows you to seamlessly record, edit, and integrate voiceovers.&lt;/p&gt;
&lt;p&gt;The popular feature, as enjoyed on TikTok and Instagram, is a staple for content creation and adds a personal touch to video creations.&lt;/p&gt;
&lt;p&gt;To get started, navigate to “Add Audio”, select “Voiceover” section and start recording. You can preview the recording, re-record it, and add more audio, such as music. Adjust the audio levels for a balanced background track.&lt;/p&gt;
&lt;p&gt;Try recording a voiceover with our Demo App for &lt;a href=&quot;https://apps.apple.com/us/app/img-ly-design-editor/id1672991141&quot;&gt;iOS&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;integrate-a-photo-editor-for-ios-and-android&quot;&gt;Integrate a Photo Editor for iOS and Android&lt;/h2&gt;
&lt;p&gt;Our new &lt;strong&gt;Photo Editor Configuration&lt;/strong&gt; is designed to offer an intuitive, out-of-the-box solution that bundles a range of key photo editing capabilities. Enhance individual photos, add text and shapes, or apply filters—this configuration is a kick-start to provide high-quality photo editing for iOS and Android with CE.SDK.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-33/photo-editor-cesdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;key-features-1&quot;&gt;Key Features&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Crop, Resize&lt;/strong&gt;&lt;br&gt;
Crop, straighten, flip, resize, and rotate your photos.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adjustments&lt;/strong&gt;&lt;br&gt;
Fine-tune your photos by adjusting brightness, contrast, and other key settings, ensuring your images look their best.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Text, Shapes, and Stickers&lt;/strong&gt;&lt;br&gt;
Enhance your photos by adding and customizing text, shapes, and stickers. Whether you’re creating eye-catching titles, intricate shapes, or playful stickers—our configuration gives you the flexibility to adjust fonts, font colors, sizes, and positions to perfectly match your vision.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Effects, Filters, Blur, Blending Modes&lt;/strong&gt;&lt;br&gt;
Transform your images with fun effects, blur, and filters. Apply overlays to add depth and texture to your photos by adjusting blend modes and opacity to achieve the perfect effect.&lt;/p&gt;
&lt;p&gt;Additionally, use our range of photo filters to set the mood, from warm and nostalgic tones to vibrant, modern effects, giving your images a distinctive and professional look.&lt;/p&gt;
&lt;p&gt;Check our &lt;a href=&quot;https://img.ly/docs/cesdk/ios/prebuilt-solutions/photo-editor-42ccb2/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;documentation&lt;/a&gt; to get started with our photo editor configuration, or &lt;a href=&quot;https://apps.apple.com/us/app/img-ly-design-editor/id1672991141&quot;&gt;try the photo editor on iOS&lt;/a&gt; and &lt;a href=&quot;https://play.google.com/store/apps/details?id=ly.img.cesdk.catalog&amp;#x26;pli=1&quot;&gt;Android&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;improvements&quot;&gt;Improvements&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Preview Audio on iOS and Android&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-33/prev-audio.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;We’ve made it easier to select the perfect audio clip for your projects. Listen to audio tracks directly within the interface before adding them to your video. Tap the play button of an audio clip in the asset library to preview it, and adjust your audio clip within the timeline.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Resize Pages&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-33/resizable-pages-short.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Resize pages in your web editor by simply grabbing corners and side handles, moving beyond the limitations of input fields or preset format sizes. This intuitive resizing integrates seamlessly with other adjustments, such as image cropping, ensuring a smooth workflow. Enable or disable this behavior as needed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Create Rounded Corners&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-33/rounded-corners-short.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;You can now easily create rounded corners for images on the web, iOS and Android. Within your designs, you can add a sleek and modern touch to your projects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Drag and Select Multiple Elements&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-33/drag-select.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;You can now click and drag with your mouse to draw a selection rectangle, instantly selecting all blocks within the covered area. This feature saves you time and effort, working with complex templates.&lt;/p&gt;
&lt;p&gt;Thanks for reading! Don’t hesitate to &lt;a href=&quot;https://img.ly/forms/contact-sales?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;reach out&lt;/a&gt; if you have any questions or need assistance.&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&quot;&gt;&lt;strong&gt;subscribe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to our newsletter.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Please note that these release notes also include improvements from previous versions.&lt;/em&gt;&lt;/p&gt;</content:encoded><dc:creator>Neslihan</dc:creator><media:content url="https://blog.img.ly/2024/08/cesdk-1-32-133-imgly.png" medium="image"/><category>Release Notes</category><category>App Development</category><category>iOS App Development</category><category>Android App Development</category><category>Design Editor</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/showcases/cesdk/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_Z11Q3oT.webp&quot; srcset=&quot;/_astro/A_New_Chart_of_History_s_Z1A1imS.webp 640w, /_astro/A_New_Chart_of_History_s_ZQ4nwl.webp 750w, /_astro/A_New_Chart_of_History_s_Z1RL1mX.webp 828w, /_astro/A_New_Chart_of_History_s_Zdfq9n.webp 1080w, /_astro/A_New_Chart_of_History_s_1uxfeA.webp 1280w, /_astro/A_New_Chart_of_History_s_1sCwTW.webp 1668w, /_astro/A_New_Chart_of_History_s_Z11Q3oT.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;p&gt;&lt;a href=&quot;https://www.youtube.com/embed/cKcksLW95-Y?feature=oembed&quot;&gt;https://www.youtube.com/embed/cKcksLW95-Y?feature=oembed&lt;/a&gt;&lt;/p&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_Zf1XyL.webp&quot; srcset=&quot;/_astro/timeline_heights-s-1_loE2x.webp 640w, /_astro/timeline_heights-s-1_1N9hmK.webp 750w, /_astro/timeline_heights-s-1_ZPCwAb.webp 828w, /_astro/timeline_heights-s-1_PsMHu.webp 1080w, /_astro/timeline_heights-s-1_Zf1XyL.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_Z1v9BvG.webp&quot; srcset=&quot;/_astro/timeline-density_Ze8fWQ.webp 640w, /_astro/timeline-density_1xRR1T.webp 750w, /_astro/timeline-density_Z1EYVqv.webp 828w, /_astro/timeline-density_UKvMA.webp 1080w, /_astro/timeline-density_Z1v9BvG.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_Zq9sal.webp&quot; srcset=&quot;/_astro/scenes-empty-full-s_Z1wkWJX.webp 640w, /_astro/scenes-empty-full-s_26v1Ib.webp 750w, /_astro/scenes-empty-full-s_ZosLXG.webp 828w, /_astro/scenes-empty-full-s_Z2nAm3m.webp 1080w, /_astro/scenes-empty-full-s_V3mUA.webp 1280w, /_astro/scenes-empty-full-s_Z1blOTE.webp 1668w, /_astro/scenes-empty-full-s_Zq9sal.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_Z1THQer.webp&quot; srcset=&quot;/_astro/hit-area_Z1Qmzes.webp 640w, /_astro/hit-area_JoIVh.webp 750w, /_astro/hit-area_Z1I3V8z.webp 828w, /_astro/hit-area_Z1VwXEK.webp 1080w, /_astro/hit-area_Z1THQer.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_Z1UocRe.webp&quot; srcset=&quot;/_astro/triangle_Z1UocRe.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;</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>Insights</category></item><item><title>How to Load Stripe Data into Google BigQuery</title><link>https://img.ly/blog/how-to-load-stripe-data-into-google-bigquery/</link><guid isPermaLink="true">https://img.ly/blog/how-to-load-stripe-data-into-google-bigquery/</guid><description>Discover how IMG.LY leverages Stripe&apos;s Data Pipeline to seamlessly transfer data into Google BigQuery using Google Cloud Functions.</description><pubDate>Thu, 18 Jul 2024 10:04:26 GMT</pubDate><content:encoded>&lt;p&gt;At IMG.LY, we recognize that leveraging data is essential for driving innovation and growth. To optimize our data for reporting, we consolidate multiple data sources, including Stripe billing and financial data, into Google BigQuery.&lt;/p&gt;
&lt;p&gt;IMG.LY is the leading provider of creative editing SDKs for &lt;a href=&quot;https://img.ly/products/video-sdk/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=stripebigquery&quot;&gt;video&lt;/a&gt;, &lt;a href=&quot;https://img.ly/products/photo-sdk/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=stripebigquery&quot;&gt;photo&lt;/a&gt;, and &lt;a href=&quot;https://img.ly/products/creative-sdk/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=stripebigquery&quot;&gt;design templates&lt;/a&gt;. While this article may not directly relate to media creation, we believe in empowering developers through knowledge sharing. Let’s dive in.&lt;/p&gt;
&lt;p&gt;Until now, we’ve relied on &lt;a href=&quot;https://www.fivetran.com&quot;&gt;Fivetran&lt;/a&gt; to fetch our data from Stripe and store it in Google BigQuery. Fivetran uses Stripe’s API, calling each endpoint, iterating over all resources, and storing the results in BigQuery (or any other supported data warehouse). While this generally works well, issues can arise. For instance, we sometimes create Stripe Subscriptions using inline pricing with &lt;a href=&quot;https://docs.stripe.com/api/subscription_items/create#create_subscription_item-price_data&quot;&gt;the &lt;code&gt;price_data&lt;/code&gt; parameter&lt;/a&gt;. This generates a new &lt;code&gt;Price&lt;/code&gt; object in Stripe on-the-fly and immediately sets it to &lt;code&gt;active: false&lt;/code&gt;. Consequently, the &lt;code&gt;Price&lt;/code&gt; object is not returned by Stripe API’s price endpoint, leading to missing data in our warehouse. Although Fivetran’s support was exceptional in resolving this issue within a day, it highlighted a potential flaw in relying solely on ETL services for data extraction.&lt;/p&gt;
&lt;p&gt;Recently, Stripe introduced &lt;a href=&quot;https://stripe.com/data-pipeline&quot;&gt;Data Pipeline&lt;/a&gt;, its own service for transferring Stripe data into a data warehouse. This ensures complete, reliable data without needing a third-party service to read Stripe’s API. Additionally, you can receive test environment data and access several tables not available via the API. For a comprehensive summary of the available data, &lt;a href=&quot;https://dashboard.stripe.com/stripe-schema&quot;&gt;refer to Stripe’s official data schema&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Currently, Stripe supports only Snowflake and Amazon Redshift as data warehouses. However, they’ve recently added the option to &lt;a href=&quot;https://docs.stripe.com/stripe-data/access-data-in-warehouse/cloud-storage/google-cloud-storage&quot;&gt;deliver data as Parquet files into Google Cloud Storage (GCS)&lt;/a&gt;. The next step for us was to import this data into Google BigQuery.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-stripe-data-pipeline-with-google-cloud-storage&quot;&gt;Setting Up Stripe Data Pipeline with Google Cloud Storage&lt;/h2&gt;
&lt;p&gt;Stripe is renowned for its excellent developer experience, and this beta feature is no exception. Enabling it within the Stripe Dashboard is quick, and the &lt;a href=&quot;https://docs.stripe.com/stripe-data/access-data-in-warehouse/cloud-storage/google-cloud-storage&quot;&gt;documentation&lt;/a&gt; is straightforward. After following the instructions and enabling the feature, it takes a while for data to appear in GCS. Once available, a complete data dump is provided every 6 hours, structured as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;At the root level, Stripe creates a folder representing the date and time of the latest transfer, e.g., &lt;code&gt;2024071600&lt;/code&gt; (&lt;code&gt;YYYYMMDDHH&lt;/code&gt;), representing the 12 am push on July 16, 2024.&lt;/li&gt;
&lt;li&gt;One level deeper, there are two folders: &lt;code&gt;livemode&lt;/code&gt; and &lt;code&gt;testmode&lt;/code&gt;, representing live and test data, respectively.&lt;/li&gt;
&lt;li&gt;Each folder contains one folder per data table, e.g., &lt;code&gt;subscriptions&lt;/code&gt; or &lt;code&gt;invoices&lt;/code&gt;. Additionally, a &lt;code&gt;coreapi_SUCCESS&lt;/code&gt; file indicates successful data transfer to your GCS bucket and readiness for consumption.&lt;/li&gt;
&lt;li&gt;Within the table folders are several Parquet files containing the actual data for each table.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;loading-the-data-from-google-cloud-storage-into-google-bigquery&quot;&gt;Loading the Data from Google Cloud Storage into Google BigQuery&lt;/h2&gt;
&lt;p&gt;There are multiple ways to transfer data from GCS to BigQuery. We opted for the following approach:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Using Google Cloud Scheduler to publish a message to Google Pub/Sub every 6 hours at 1 am, 7 am, 1 pm, and 7 pm.&lt;/li&gt;
&lt;li&gt;Creating a Google Cloud Function that listens for new messages on the above Pub/Sub topic. When a message is received, it triggers a Node.js script that loads the most recent data from GCS into BigQuery and deletes it from GCS.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let’s delve into the details.&lt;/p&gt;
&lt;h3 id=&quot;create-a-google-cloud-scheduler-job&quot;&gt;Create a Google Cloud Scheduler Job&lt;/h3&gt;
&lt;p&gt;First, create a new Cloud Scheduler job &lt;a href=&quot;https://console.cloud.google.com/cloudscheduler/jobs/new&quot;&gt;here&lt;/a&gt; with the following configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Name&lt;/strong&gt;: Choose a name for this job.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Region&lt;/strong&gt;: The region is not crucial for this task; we used &lt;code&gt;europe-west3&lt;/code&gt; since most of our services are in Germany.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Frequency&lt;/strong&gt;: We want the job to run every 6 hours at 1 am, 7 am, 1 pm, and 7 pm. Stripe publishes data every 6 hours, but it takes time to transfer it to GCS. We chose 1 hour later than Stripe’s push time, so our value is &lt;code&gt;0 1,7,13,19 * * *&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timezone&lt;/strong&gt;: Choose ‘Coordinated Universal Time (UTC)’.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Target type&lt;/strong&gt;: Choose ‘Pub/Sub’.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Select a Cloud Pub/Sub topic&lt;/strong&gt;: Select or create a new Pub/Sub topic using the default configuration. This is used to trigger the Cloud Function.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Message body&lt;/strong&gt;: For this task, we don’t look at the contents of the message, as such the content of this value doesn’t matter. We opted for a simple &lt;code&gt;load&lt;/code&gt; string.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 566px) 566px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;566&quot; height=&quot;1240&quot; src=&quot;https://img.ly/_astro/Screenshot-2024-07-16-at-11.46.22_1dcdSQ.webp&quot; srcset=&quot;/_astro/Screenshot-2024-07-16-at-11.46.22_1dcdSQ.webp 566w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Finally, click ‘Create’ to set up the scheduler. Now, a message is published to the selected Pub/Sub topic every 6 hours. Next, we need to respond to this message.&lt;/p&gt;
&lt;h3 id=&quot;create-a-google-cloud-function&quot;&gt;Create a Google Cloud Function&lt;/h3&gt;
&lt;p&gt;Create a Google Cloud Function triggered by Pub/Sub &lt;a href=&quot;https://console.cloud.google.com/functions/add&quot;&gt;here&lt;/a&gt; with the following configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Environment&lt;/strong&gt;: Choose ‘2nd gen’.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Function name&lt;/strong&gt;: Choose a name for this Cloud function.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Region&lt;/strong&gt;: Select the region for the function, typically europe-west3 for our services.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trigger type&lt;/strong&gt;: Choose ‘Cloud Pub/Sub’.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloud Pub/Sub topic&lt;/strong&gt;: Select the Pub/Sub topic created in the previous step.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Adjust the ‘Runtime, build, connections and security settings’ based on your Cloud setup and the required processing power for Stripe data. Generally, the following settings work well:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Memory allocated&lt;/strong&gt;: ‘512 MiB’&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CPU&lt;/strong&gt;: ‘1’&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timeout&lt;/strong&gt;: ‘540’&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minimum number of instances&lt;/strong&gt;: ‘0’ (to ensure the function shuts down when not in use)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maximum number of instances&lt;/strong&gt;: ‘1’&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Service account&lt;/strong&gt;: Use or create a service account with permissions to access the GCS bucket where Stripe data is stored and the BigQuery datasets to load the data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ingress settings&lt;/strong&gt;: Choose ‘Allow internal traffic only’.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 554px) 554px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;554&quot; height=&quot;1286&quot; src=&quot;https://img.ly/_astro/Screenshot-2024-07-16-at-11.56.55_1Iq5S7.webp&quot; srcset=&quot;/_astro/Screenshot-2024-07-16-at-11.56.55_1Iq5S7.webp 554w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Click ‘Next’ to provide the function’s code. Select:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Runtime&lt;/strong&gt;: ‘Node.js 20’&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Source code&lt;/strong&gt;: ‘Inline Editor’&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entry point&lt;/strong&gt;: &lt;code&gt;loadStripeData&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the &lt;code&gt;package.json&lt;/code&gt;, add the BigQuery and Cloud Storage Node.js packages:&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;index.js&lt;/code&gt;, add the following code:&lt;/p&gt;

&lt;p&gt;This script does the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;For each environment (live and test), it searches for the latest folder containing a &lt;code&gt;coreapi_SUCCESS&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;For each table, it groups all related Parquet files and loads them into the BigQuery table using &lt;code&gt;WRITE_TRUNCATE&lt;/code&gt;, which overwrites existing data. Note that the location is specified as &lt;code&gt;EU&lt;/code&gt;, matching our BigQuery dataset and GCS bucket location. Adjust this parameter if your data is elsewhere.&lt;/li&gt;
&lt;li&gt;If all files for an environment are loaded without errors, the files are deleted from GCS. This step is optional; if you prefer to keep a backup, you can omit this part.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Click ‘Deploy’ to deploy your Cloud function.&lt;/p&gt;
&lt;h3 id=&quot;create-bigquery-datasets&quot;&gt;Create BigQuery Datasets&lt;/h3&gt;
&lt;p&gt;The final step is to create two datasets in Google BigQuery. Open &lt;a href=&quot;https://console.cloud.google.com/bigquery&quot;&gt;Google BigQuery&lt;/a&gt;, click on the three dots next to your project’s name, and select ‘Create dataset’. Enter a name and choose a location matching your GCS bucket’s location. Repeat this process for the test dataset.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Following these steps will ensure your Stripe data is imported into BigQuery and automatically updated every 6 hours. However, as Data Pipeline for GCS is still in beta, there are some limitations. For example, the schema of the Parquet files lacks type annotations for timestamps, so all timestamps in BigQuery are represented as &lt;code&gt;INTEGER&lt;/code&gt; instead of &lt;code&gt;TIMESTAMP&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Additionally, some tables, such as &lt;code&gt;subscription_item_change_events&lt;/code&gt;, are not currently transferred when syncing with Google Cloud Storage, although this issue is expected to be resolved soon. Meanwhile, we continue to use Fivetran in conjunction with the above method to sync Stripe data to Google BigQuery and plan to fully migrate to Data Pipeline once it exits the beta phase.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thank you for reading!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3,000+ creative professionals gain exclusive access and hear of our releases first—&lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;subscribe&lt;/a&gt; to our newsletter and never miss out.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Sascha</dc:creator><media:content url="https://blog.img.ly/2024/07/stripe-bigquery-how-to.jpg" medium="image"/><category>How-To</category><category>Business Intelligence</category><category>Data</category><category>Cloud</category><category>Insights</category></item><item><title>Background Removal in the Browser Using ONNX Runtime with WebGPU</title><link>https://img.ly/blog/browser-background-removal-using-onnx-runtime-webgpu/</link><guid isPermaLink="true">https://img.ly/blog/browser-background-removal-using-onnx-runtime-webgpu/</guid><description>Achieve 20x Faster Background Removal in the Browser</description><pubDate>Tue, 11 Jun 2024 16:26:17 GMT</pubDate><content:encoded>&lt;p&gt;TL;DR: Using ONNX Runtime with WebGPU and WebAssembly leads to 20x speedup over multi-threaded and 550x speedup over single-threaded CPU performance. Thus achieving interactive speeds for state-of-the-art background removal directly in the browser.&lt;/p&gt;
&lt;p&gt;Removing background from an image is a typical job to be done in creative editing. We have come a long way from manually knocking out the background from an image to full automation with Neural Networks.&lt;/p&gt;
&lt;p&gt;Most state-of-the-art background removal solutions work by offloading the task to the server with a GPU as it was simply infeasible to run the NN on the client.&lt;/p&gt;
&lt;p&gt;However, running background removal directly in the browser offers several advantages over server-side processing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reduced server load and infrastructure costs by offloading heavy lifting to the client.&lt;/li&gt;
&lt;li&gt;Enhanced scalability by distributing the workload across client devices.&lt;/li&gt;
&lt;li&gt;Easier compliance with data protection and security policies by not transferring data across a network to a server.&lt;/li&gt;
&lt;li&gt;Offline processing without needing a reliable internet connection.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It caters to a wide range of use cases, including but not limited to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;E-commerce applications&lt;/em&gt; that need to remove backgrounds from product images in real time.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Image editing applications&lt;/em&gt; that require background removal capabilities for enhancing user experience.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Web-based graphic design tools&lt;/em&gt; that aim to simplify the creative process with in-browser background removal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In general, two factors influence the feasibility of running background removal directly on the client.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The execution performance, and&lt;/li&gt;
&lt;li&gt;the download size of the Neural Network.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The performance or overall runtime is the major factor to be useful in interactive applications, if a user has to wait several minutes or hours for a neural network to execute, this is in many cases far too long in terms of good user experience. From experience, there are three factors to consider.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The initial first-time execution. The major factor is that neural networks come with the drawback of generally being several MB to GB in size, thus the time to download the neural network into the browser cache is considerable. In subsequent browser page reloads this has no impact anymore.&lt;/li&gt;
&lt;li&gt;The neural network or session initialization time, cannot be cached and has to run with every reload of the page in the browser.&lt;/li&gt;
&lt;li&gt;The neural network or session inference time, largely depends on the longest path inside the neural network and most importantly the execution time of each operator in the neural network.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;towards-real-time-background-removal-in-the-browser&quot;&gt;Towards Real-time Background Removal in the Browser&lt;/h3&gt;
&lt;p&gt;Neural networks are commonly trained in frameworks like PyTorch, which is a neural network library for Python, as such not usable directly in the browser. The best option to run neural networks directly in the browser is converting the neural network into the &lt;strong&gt;Open Neural Network Exchange (ONNX)&lt;/strong&gt; format, which is a widely supported standardized format by Microsoft used extensively in the industry.&lt;/p&gt;
&lt;p&gt;These ONNX-formatted neural networks can then be reconverted into a platform-specific format or directly executed by a supported runtime.&lt;/p&gt;
&lt;p&gt;The ONNX Runtime by Microsoft is a high-performance inference engine designed to run ONNX models across various platforms and languages. One notable feature is &lt;a href=&quot;https://onnxruntime.ai/docs/tutorials/web/build-web-app.html&quot;&gt;ONNX Runtime Web&lt;/a&gt;, which allows JavaScript developers to execute ONNX models directly in the browser. ONNX Runtime Web offers several execution providers for hardware acceleration. For instance, its WebAssembly execution provider enhances CPU execution performance using multiple Web Workers and SIMD instructions.&lt;/p&gt;
&lt;p&gt;More importantly, starting from version 1.7.0, ONNX Runtime Web includes official support for the WebGPU execution provider. WebGPU is a modern web API that enables developers to utilize GPU power for high-performance computations, offering a significant performance boost over CPU-based in-browser machine learning. WebGPU support has been available by default since Chrome 113 and Edge 113 on Mac, Windows, and ChromeOS, and Chrome 121 on Android. For the latest browser support updates, you can track them &lt;a href=&quot;https://github.com/gpuweb/gpuweb/wiki/Implementation-Status&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;implementation-details&quot;&gt;Implementation Details&lt;/h3&gt;
&lt;p&gt;For the implementation of the open-source package &lt;a href=&quot;https://github.com/imgly/background-removal-js&quot;&gt;@imgly/background-removal-js&lt;/a&gt;, we started the journey with a neural network implementation in PyTorch written in Python. The network was then converted to ONNX. You can see our &lt;a href=&quot;https://img.ly/showcases/cesdk/background-removal/web&quot;&gt;live showcase&lt;/a&gt; here.&lt;/p&gt;
&lt;p&gt;The original model was using 32-bit floating point (fp32) precision, which is fine, but results in a file size of 168 MB after converting it to ONNX. As mentioned earlier, the size of the network has a large impact on perceived first-time execution performance as the download time tends to be longer than the execution time, but more to that later.&lt;/p&gt;
&lt;p&gt;To reduce the size of the model, we converted the model to use fp16 (16-bit floating point) and QUINT8 (Quantized 8-bit) datatypes. Thus, effectively reducing the size to half (84MB) and a fourth (42MB) of the original size. Additionally to the download size, the operators used will be converted corresponding to the datatype and different data types and depending on the hardware may lead to speed improvements or even deteriorating due to specialized hardware being used or not being present.&lt;/p&gt;
&lt;p&gt;Note, that while that sounds great, the conversion has a potential negative impact on the quality of the output as we are removing information in the neural networks and since we are working with images, artifacts might become visible and the quality of the resulting background mask is reduced.&lt;/p&gt;
&lt;h2 id=&quot;evaluation&quot;&gt;Evaluation&lt;/h2&gt;
&lt;p&gt;When dealing with neural networks in the browser we can identify three different scenarios&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;First Use&lt;/li&gt;
&lt;li&gt;First Run&lt;/li&gt;
&lt;li&gt;Consecutive Runs&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first-use scenario occurs when the web application is started the first time. The neural network has to be downloaded from the server into the browser sandbox, as neural networks are several 10-1000 MB in size this is not neglectable.&lt;/p&gt;
&lt;p&gt;The first run assumes that the neural network is already present in the browser cache, however, when the neural network ought to be used, the network has to initialize before execution.&lt;/p&gt;
&lt;p&gt;In consecutive runs, the neural network is already in memory and the execution time is largely determined by the neural network depth and operators only.&lt;/p&gt;
&lt;h3 id=&quot;first-use--neural-network-download&quot;&gt;First Use – Neural Network Download&lt;/h3&gt;
&lt;p&gt;While download or time is a large factor in the first-time execution time, this is largely dependent on the available network bandwidth, as such it is not part of the evaluation but in order to get an idea here are the expected download times for the fp32 (168MB) and fp16 (84MB) neural network subject to various common network bandwidth:&lt;/p&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Network Bandwidth&lt;/th&gt;&lt;th&gt;Filesize&lt;/th&gt;&lt;th&gt;Download Time&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;10 Mbps&lt;/td&gt;&lt;td&gt;84 MB&lt;/td&gt;&lt;td&gt;67s s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;100 Mbps&lt;/td&gt;&lt;td&gt;84 MB&lt;/td&gt;&lt;td&gt;6.7 s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1 Gbps&lt;/td&gt;&lt;td&gt;84 MB&lt;/td&gt;&lt;td&gt;0.67 s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;10 Gbps&lt;/td&gt;&lt;td&gt;84 MB&lt;/td&gt;&lt;td&gt;0.067&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Network Bandwidth&lt;/th&gt;&lt;th&gt;Filesize&lt;/th&gt;&lt;th&gt;Download Time&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;10 Mbps&lt;/td&gt;&lt;td&gt;168 MB&lt;/td&gt;&lt;td&gt;134.4 s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;100 Mbps&lt;/td&gt;&lt;td&gt;168 MB&lt;/td&gt;&lt;td&gt;13.4 s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1 Gbps&lt;/td&gt;&lt;td&gt;168 MB&lt;/td&gt;&lt;td&gt;1.34 s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;10 Gbps&lt;/td&gt;&lt;td&gt;168 MB&lt;/td&gt;&lt;td&gt;0.13 s&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Based on the assumption that the median download bandwidth is ~100 Mbps, we see that it’s in the 5-15 second range.&lt;/p&gt;
&lt;h3 id=&quot;first-run--neural-network-initialization--compilation&quot;&gt;First Run – Neural Network Initialization / Compilation&lt;/h3&gt;
&lt;p&gt;Before the neural network can be executed it has to be initialized. Initialization includes several execution provider-specific steps. Most prominent are the time to upload or convert the data to the execution provider and execution provider-specific ONNX graph optimization passes. This all adds to the first run experience. We have evaluated the average session initialization time for the CPU (WASM) and WebGPU provider on a MacBook Pro 13” from 2024 with an Apple M3 Max 16 cores to get an idea of the general impact on first run execution time:&lt;/p&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Device&lt;/th&gt;&lt;th&gt;Datatype&lt;/th&gt;&lt;th&gt;Session Initialization Time&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;fp32&lt;/td&gt;&lt;td&gt;~320ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;fp16&lt;/td&gt;&lt;td&gt;~320ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WebGPU&lt;/td&gt;&lt;td&gt;fp32&lt;/td&gt;&lt;td&gt;~400ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WebGPU&lt;/td&gt;&lt;td&gt;fp16&lt;/td&gt;&lt;td&gt;~200ms&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Note, that session initialization is not negligible and adds significant runtime overhead and might be subject to additional optimization possibilities like caching the optimized model.&lt;/p&gt;
&lt;h3 id=&quot;consecutive-runs--neural-network-execution&quot;&gt;Consecutive Runs – Neural Network Execution&lt;/h3&gt;
&lt;p&gt;Independent of the download and initialization time, we evaluated different execution providers on a MacBook Pro 13” from 2024 with an Apple M3 Max 16 cores. While this is top-end consumer hardware, the general trends will probably apply to various hardware configurations. As a reference, we choose the single thread performance with the neural network running on the CPU with 1 worker thread and SIMD disabled.&lt;/p&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Device&lt;/th&gt;&lt;th&gt;SIMD&lt;/th&gt;&lt;th&gt;Threads&lt;/th&gt;&lt;th&gt;Datatype&lt;/th&gt;&lt;th&gt;Session Runtime&lt;/th&gt;&lt;th&gt;Speedup&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;fp32&lt;/td&gt;&lt;td&gt;~53000 ms&lt;/td&gt;&lt;td&gt;1.0 x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;16&lt;/td&gt;&lt;td&gt;fp32&lt;/td&gt;&lt;td&gt;~6300 ms&lt;/td&gt;&lt;td&gt;8.4 x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;fp32&lt;/td&gt;&lt;td&gt;~15000 ms&lt;/td&gt;&lt;td&gt;3.5 x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;16&lt;/td&gt;&lt;td&gt;fp32&lt;/td&gt;&lt;td&gt;~2000 ms&lt;/td&gt;&lt;td&gt;26.5 x&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The data above reveals that running the neural network without any acceleration such as SIMD and threading in the browser results in almost 53s runtime, and as such is for most interactive use cases too slow to use. Due to the optimizations of the ONNX Runtime that uses SIMD and threads, we can achieve an overall speedup of roughly ~26 times compared to the baseline performance. Thus decreasing the session runtime to around 2s and making it usable for interactive applications.&lt;/p&gt;
&lt;p&gt;As mentioned before, we neglected the download time and size of the network. Leveraging the fp16 model compression, we re-ran the benchmarks and got similar results as before, but with half the bandwidth required to download the network for the first time application. The general visual performance of the fp16 and fp32 is similar or visually not perceivable. The quint8 model led to artifacts and as such unusable for visual processing, thus we excluded from the following benchmark.&lt;/p&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Device&lt;/th&gt;&lt;th&gt;SIMD&lt;/th&gt;&lt;th&gt;Threads&lt;/th&gt;&lt;th&gt;Datatype&lt;/th&gt;&lt;th&gt;Session Runtime&lt;/th&gt;&lt;th&gt;Speedup&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;fp16&lt;/td&gt;&lt;td&gt;~55000 ms&lt;/td&gt;&lt;td&gt;1.0 x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;16&lt;/td&gt;&lt;td&gt;fp16&lt;/td&gt;&lt;td&gt;~7300 ms&lt;/td&gt;&lt;td&gt;7.2 x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;fp16&lt;/td&gt;&lt;td&gt;~15000 ms&lt;/td&gt;&lt;td&gt;3.5 x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;16&lt;/td&gt;&lt;td&gt;fp16&lt;/td&gt;&lt;td&gt;~2300 ms&lt;/td&gt;&lt;td&gt;23.9 x&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The results are a little worse than the fp32 version, which might be because the fp16 datatype has no direct specialized hardware in modern CPUs like the M3 Max CPU, and as such additional fp16 to fp32 conversion operations have to be performed.&lt;/p&gt;
&lt;p&gt;Our final benchmark measures the WebGPU performance, which led to the following impressive results. To have a fair comparison and understanding of the impact of the WebGPU technology, we compare it with the best CPU version with 16 threads and SIMD enabled with the fp32 model, which was around ~2 s.&lt;/p&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Device&lt;/th&gt;&lt;th&gt;SIMD&lt;/th&gt;&lt;th&gt;Threads&lt;/th&gt;&lt;th&gt;Datatype&lt;/th&gt;&lt;th&gt;Session Runtime&lt;/th&gt;&lt;th&gt;Speedup&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;WebGPU&lt;/td&gt;&lt;td&gt;Not applicable&lt;/td&gt;&lt;td&gt;Not applicable&lt;/td&gt;&lt;td&gt;fp32&lt;/td&gt;&lt;td&gt;~120ms&lt;/td&gt;&lt;td&gt;16.6 x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WebGPU&lt;/td&gt;&lt;td&gt;Not applicable&lt;/td&gt;&lt;td&gt;Not applicable&lt;/td&gt;&lt;td&gt;fp16&lt;/td&gt;&lt;td&gt;~100ms&lt;/td&gt;&lt;td&gt;20.0 x&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The WebGPU performance varies around &lt;strong&gt;16 to 20 x&lt;/strong&gt; improvements over the best CPU execution time. The GPU has specialized hardware for fp16 instructions, as such the model performs better than the fp32 model. Also, note that the session initialization time is also reduced due to half the required bandwidth to upload the network data to the GPU.&lt;/p&gt;
&lt;p&gt;Therefore, the first run of the network will take ~300 ms and consecutive runs will be ~100 ms, leading to near real-time performance in the browser.&lt;/p&gt;
&lt;p&gt;Note, that the WebGPU performance is an astonishing &lt;strong&gt;550 times faster&lt;/strong&gt; than the single thread, with no SIMD performance.&lt;/p&gt;
&lt;p&gt;Try the live implementation in our &lt;a href=&quot;https://img.ly/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=background-removal-onnx&quot;&gt;background removal showcase&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;WebGPU is a major leap in establishing the browser as a factor to be reckoned with as a true Application platform. With &lt;a href=&quot;https://IMG.LY/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=background-removal-onnx&quot;&gt;IMG.LY&lt;/a&gt;, we are striving to leverage modern technology to make design tools accessible, this includes on-device execution, on-premise, but also on-cloud execution of design tools leveraging neural networks.&lt;/p&gt;
&lt;p&gt;As a next step, we will port background removal to all our supported platforms, ONNX Runtime seems the best choice, as it is already available for all the potential platforms we support.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/onnx/bg-removal.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Furthermore, we are evaluating the feasibility of in-browser background removal for videos to be included with our video-editing suits.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://img.ly/showcases/cesdk/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=background-removal-onnx&quot;&gt;Try our tools today&lt;/a&gt; to see how we help bring unique creative editing experiences to any application. Or &lt;a href=&quot;https://img.ly/forms/contact-sales/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=background-removal-onnx&quot;&gt;contact us&lt;/a&gt; to discuss your project.&lt;/p&gt;</content:encoded><dc:creator>Daniel</dc:creator><dc:creator>Emma</dc:creator><media:content url="https://blog.img.ly/2024/06/onnx-runtime-imgly.jpg" medium="image"/><category>Plugin</category><category>App Development</category><category>Image Processing</category><category>Insights</category></item><item><title>Unleash Creativity with CE.SDK’s New Plugin System</title><link>https://img.ly/blog/img-ly-sdk-plugin-system/</link><guid isPermaLink="true">https://img.ly/blog/img-ly-sdk-plugin-system/</guid><description>Teaser: Our new Plugin System empowers customization and creativity with one-click features, smart design tools, and generative AI.</description><pubDate>Mon, 03 Jun 2024 08:42:25 GMT</pubDate><content:encoded>&lt;p&gt;At IMG.LY, we have always believed that a superb design editor should be effortlessly customizable and extensible. We are thrilled to roll out a brand-new Plugin system for CE.SDK in the upcoming months—to take creative editing and feature development to the next level.&lt;/p&gt;
&lt;p&gt;Starting with one-click features like background removal or vectorizers, smart design tools like QR codes or subtitle generators, and deeply interactive features like generative AI for text and images; all these tools can be used or built by customers soon.&lt;/p&gt;
&lt;p&gt;Additionally, our upcoming Plugin system will bring you unparalleled autonomy by making feature development for our SDK accessible and offering extensive options to reconfigure our editor’s UI.&lt;/p&gt;
&lt;p&gt;Start exploring our Plugin System rollout now to immediately benefit from upcoming features.&lt;/p&gt;
&lt;h2 id=&quot;built-for-modification&quot;&gt;Built for Modification&lt;/h2&gt;
&lt;p&gt;Let’s dive deep into some of the opportunities CE.SDK plugins help unlock.&lt;/p&gt;
&lt;h3 id=&quot;unlocking-the-ai-revolution&quot;&gt;Unlocking the AI Revolution&lt;/h3&gt;
&lt;p&gt;While the AI transformation is already fully underway, much of the tech is still not very accessible to product builders, often requiring deep technical knowledge to get started. At the same time, AI features become significantly more valuable when integrated with other editing functionalities in workflows or automation. With our plugins, we aim to make it effortless to leverage innovation and put it to use.&lt;/p&gt;
&lt;h3 id=&quot;boosting-customer-autonomy&quot;&gt;Boosting Customer Autonomy&lt;/h3&gt;
&lt;p&gt;Key to our success is providing maximum flexibility and autonomy to our customers about product decisions. Ultimately, you shouldn’t depend on our product roadmap; rather, you should be able to add features when you like. While our SDKs are already highly configurable, plugins allow tailoring the whole user experience not only on a look &amp;#x26; feel level but through custom functionalities and editing experiences.&lt;/p&gt;
&lt;h3 id=&quot;accelerate-product-expansion&quot;&gt;Accelerate Product Expansion&lt;/h3&gt;
&lt;p&gt;Many ecosystems witnessed explosive growth in added value to the user after releasing plugin mechanisms. Currently, only IMG.LY core developers can contribute to the SDK. We have started to extend this to solution engineers and even designers on our team who don’t have much knowledge of the inner workings of the SDK. Ultimately, we will push this more and more into a community of contributors, making the community’s innovation accessible to everyone.&lt;/p&gt;
&lt;h2 id=&quot;key-concepts&quot;&gt;Key Concepts&lt;/h2&gt;
&lt;p&gt;Three important concepts have driven the development of our Plugins:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Customizable Menu Bars&lt;/strong&gt;&lt;br&gt;
We are extending our API so that it allows easy hooking into various parts of the UI. Our editor has key components like the inspector, toolbar, and on-canvas menu. These are now all accessible through an API, so you can hook your feature anywhere in the editor.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Easily hook your features anywhere in the editor.&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/key-concept-plugins-sdk-1_Z7C57k.webp&quot; srcset=&quot;/_astro/key-concept-plugins-sdk-1_Z1cMp6H.webp 640w, /_astro/key-concept-plugins-sdk-1_1mLpHS.webp 750w, /_astro/key-concept-plugins-sdk-1_1vy6cU.webp 828w, /_astro/key-concept-plugins-sdk-1_Z2cAeFG.webp 1080w, /_astro/key-concept-plugins-sdk-1_Z13AeBp.webp 1280w, /_astro/key-concept-plugins-sdk-1_2dEjpa.webp 1668w, /_astro/key-concept-plugins-sdk-1_Z7C57k.webp 1920w&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UI Building Blocks to Provide Consistency&lt;/strong&gt;&lt;br&gt;
To reach a high level of consistency and speed up time for development, we will be providing out-of-the-box UI components such as buttons, sliders, text inputs, etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Escape Hatches&lt;/strong&gt;&lt;br&gt;
From experience, we know that sometimes unique functionality needs unique solutions, so we have added escape hatches to add custom elements via HTML whenever needed.&lt;/p&gt;
&lt;h2 id=&quot;what-can-you-build-with-our-plugin-system&quot;&gt;What Can You Build with our Plugin System?&lt;/h2&gt;
&lt;p&gt;Let’s explore some potential use cases of the plugin system.&lt;/p&gt;
&lt;h3 id=&quot;custom-actions&quot;&gt;Custom Actions&lt;/h3&gt;
&lt;p&gt;Adding custom actions is a great option to make simple third-party APIs accessible within the editor. This can be &lt;strong&gt;one-click edits&lt;/strong&gt; such as background removal, vectorizers, or auto-enhancement for images. You can also add custom actions for text in combination with Large Language Models (LLM) to provide features like autocorrection and improved writing, etc.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/plugin-release/background-removal-plugin-sdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;custom-tools&quot;&gt;Custom Tools&lt;/h3&gt;
&lt;p&gt;Some custom functionality will require more than just a single button, e.g., to &lt;strong&gt;generate AI images&lt;/strong&gt;, background patterns, QR codes, or maps. In these cases, you’ll require sliders, text input, drop-downs, and many other UI elements. With plugins, you can easily create panels with your own UI to bring any custom tool to life.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/plugin-release/ai-generator-plugin-sdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;custom-assets--presets&quot;&gt;Custom Assets &amp;#x26; Presets&lt;/h3&gt;
&lt;p&gt;Apart from building custom tools, you can also bundle and group effects into presets and make them accessible in a custom panel. This is especially useful to simplify the design process or create standard design components: for example, providing beautiful text presets will enable your users to create instantly great text designs without any design knowledge.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Bundle presets or sticker packs for a stylish, simple design process.&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/custom-bundles-sdk-s_Z2eX5Wk.webp&quot; srcset=&quot;/_astro/custom-bundles-sdk-s_wWPTG.webp 640w, /_astro/custom-bundles-sdk-s_WbFjy.webp 750w, /_astro/custom-bundles-sdk-s_Zx5C9.webp 828w, /_astro/custom-bundles-sdk-s_Z1MpguG.webp 1080w, /_astro/custom-bundles-sdk-s_1RCU0T.webp 1280w, /_astro/custom-bundles-sdk-s_Z1MVQn1.webp 1668w, /_astro/custom-bundles-sdk-s_Z2eX5Wk.webp 1920w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;custom-libraries&quot;&gt;&lt;strong&gt;Custom Libraries&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Integrate third-party libraries, such as Unsplash, Getty Images, Pexels, or your own.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/plugin-release/photo-library-sdk-unsplash.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;custom-editor-behavior&quot;&gt;Custom Editor Behavior&lt;/h3&gt;
&lt;p&gt;Some of our customers asked us how they could move a functionality from one place in the editor to another. Let’s say you wish to move the function ‘move to front’ from the inspector to the canvas menu. This is not a problem! You can do this by using the internal API endpoints of our editor.&lt;/p&gt;
&lt;p&gt;As for custom editor behavior, you can do far more than just move functionality. Here is a demo of layer lists we built as a plugin.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/plugin-release/layer-list-editor-sdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;custom-user-feedback&quot;&gt;Custom User Feedback&lt;/h3&gt;
&lt;p&gt;Additionally, you can enhance the canvas with overlays, which are useful for providing alerts, instructions, or feedback directly on the canvas.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Provide instant design feedback to users, such as cut-off text or images.&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/custom-user-notification-design-feedback-1_Z1dtpGM.webp&quot; srcset=&quot;/_astro/custom-user-notification-design-feedback-1_1qQrVb.webp 640w, /_astro/custom-user-notification-design-feedback-1_yfu3B.webp 750w, /_astro/custom-user-notification-design-feedback-1_Z2ctvGd.webp 828w, /_astro/custom-user-notification-design-feedback-1_1CxUVl.webp 1080w, /_astro/custom-user-notification-design-feedback-1_29zsPe.webp 1280w, /_astro/custom-user-notification-design-feedback-1_Z81FNb.webp 1668w, /_astro/custom-user-notification-design-feedback-1_Z1dtpGM.webp 1920w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;whats-next&quot;&gt;What’s Next&lt;/h2&gt;
&lt;p&gt;We are now rolling out Plugins and building an initial set of features through Plugins ourselves—available for the web first, and mobile SDKs will follow. Keep your eyes peeled for our next releases and don’t hesitate to &lt;a href=&quot;https://img.ly/forms/contact-sales&quot;&gt;get in touch&lt;/a&gt; with us to learn more about plugins, and how your product benefits from integration without losing time and resources.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thank you for reading. Join 3,000+ creative professionals—&lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;subscribe&lt;/a&gt; to our newsletter for updates on new features, plugins, early access, and more!&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Daniel</dc:creator><dc:creator>Eray</dc:creator><media:content url="https://blog.img.ly/2024/05/plugin-sdk-design-img-ly-s.jpg" medium="image"/><category>Plugin</category><category>App Development</category><category>Design Editor</category><category>Company</category></item><item><title>CE.SDK v1.25 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v-1-25-0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v-1-25-0-release-notes/</guid><description>Recolor images, such as T-shirt mockups, remove green screen backgrounds, and preview audio directly in your app. </description><pubDate>Tue, 07 May 2024 11:43:59 GMT</pubDate><content:encoded>&lt;p&gt;Welcome to the latest update from our team! Since our &lt;a href=&quot;https://img.ly/blog/creative-editor-sdk-v-1-23-0-release-notes/&quot;&gt;last release&lt;/a&gt;, we have been working to bring more creative capabilities to your app and improve user experience. With this release, you can:&lt;/p&gt;
&lt;h2 id=&quot;recolor-images-like-t-shirt-mockups&quot;&gt;Recolor Images like T-shirt Mockups&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-25/recolor-images-editor-sdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Replace colors in any image with our new recoloring feature. Select a color you want to change, choose its replacement, and apply the changes. Recoloring is ideal for tasks like altering the color of specific elements, such as t-shirts in product photos.&lt;/p&gt;
&lt;p&gt;Simply choose your image, navigate to Effects, and select “Recolor”. Choose the color you want to change (Source Color), and the color you want to replace it with (Target Color). For a more refined result, adjust “Smoothness”, “Color Match”, and “Brightness Match”.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-25/recoloring_androids.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;This feature is available on &lt;strong&gt;Web&lt;/strong&gt;, &lt;strong&gt;Android&lt;/strong&gt;, and &lt;strong&gt;iOS&lt;/strong&gt; platforms.&lt;/p&gt;
&lt;p&gt;Check our &lt;a href=&quot;https://img.ly/docs/cesdk/js/filters-and-effects/add-c796ba/&quot;&gt;documentation&lt;/a&gt; on filters and effects to learn more.&lt;/p&gt;
&lt;h2 id=&quot;create-transparency-with-a-green-screen&quot;&gt;Create Transparency with a Green Screen&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-25/green-screen-video-sdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Easily make green screen backgrounds transparent in your &lt;strong&gt;images&lt;/strong&gt; and &lt;strong&gt;videos on the Web,&lt;/strong&gt; and for images on &lt;strong&gt;Android and iOS&lt;/strong&gt;. Our Green Screen Effect is tailored to identify and eliminate green backdrops—or any other color you specify. Perfect for content creators and videographers who need to isolate subjects without manually editing backgrounds.&lt;/p&gt;
&lt;p&gt;Select an image or video clip with a color background you wish to remove. Then choose “Green Screen” in the Effects, and our effect handles the rest. Fine-tune the effect to your liking.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-25/greenscreen_android.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h2 id=&quot;user-interface-improvements&quot;&gt;User Interface Improvements&lt;/h2&gt;
&lt;p&gt;In our latest update, we’ve focused on enhancing the usability and functionality of our interface. Here’s what’s new:&lt;/p&gt;
&lt;h3 id=&quot;audio-preview&quot;&gt;Audio Preview&lt;/h3&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-25/audio-preview-web-video-sdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Choosing the right audio clip is now easier with our new Audio Preview feature. Preview audio clips directly within the interface and make the perfect selection for your projects.&lt;/p&gt;
&lt;h3 id=&quot;selection-frame-improvements&quot;&gt;Selection Frame Improvements&lt;/h3&gt;
&lt;p&gt;We’ve upgraded our selection frames with new icons, hover effects, enhanced drag functionality, and shadow rendering. These improvements make manipulating elements within our platform more intuitive and visually appealing. Whether you’re rearranging components or resizing elements, our refined handling ensures a smoother interaction.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Please note that these release notes also include improvements from v1.24.&lt;/em&gt;&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, early access, and updates.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Neslihan</dc:creator><media:content url="https://blog.img.ly/2024/05/creative-sdk-1-25.jpg" medium="image"/><category>Release Notes</category><category>CE.SDK</category><category>Video Editing</category><category>Design Editor</category><category>App Development</category></item><item><title>CE.SDK v1.19 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v1-19-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v1-19-release-notes/</guid><description>Explore unified editing of your graphic blocks, new showcases, and an exciting announcement for video!</description><pubDate>Fri, 22 Dec 2023 14:26:48 GMT</pubDate><content:encoded>&lt;p&gt;Since our last release, we’ve been crafting new features to empower your users’ creative journey. Today, we’re thrilled to introduce CE.SDK v1.19! With this release, you can:&lt;/p&gt;
&lt;h3 id=&quot;unify-design-power-with-block-unification&quot;&gt;Unify Design Power with Block Unification&lt;/h3&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-19/block-unification_1-19-videofills.mp4&quot; controls muted playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Introducing Block Unification for CE.SDK on Mobile and Web—a feature that simplifies design versatility. Videos, images, shapes, and stickers now seamlessly come together as one Graphic Block, easily modified within a unified inspector. All supported settings for your selected block, including strokes, filters, and adjustments, are conveniently displayed in a single, user-friendly space.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unified Graphic Block&lt;/strong&gt;&lt;br&gt;
Experience a singular Graphic Block supporting diverse fills (images, videos, colors, gradients) and shapes. Switch fill types (video, image, color) effortlessly, enabling dynamic designs in one place.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Easy Fine-Tuning&lt;/strong&gt;&lt;br&gt;
Block Unification integrates effects, filters, adjustments, and blur uniformly across all design elements. Elevate your designs with precision and consistency.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A Treat for Users and Developers&lt;/strong&gt;&lt;br&gt;
For developers, Block Unification means streamlined code maintenance. The consolidation of design blocks into one Graphic Block simplifies development, allowing more focus on crafting exceptional design experiences with IMG.LY.&lt;/p&gt;
&lt;h3 id=&quot;enhance-interaction-with-mouse-wheel-support&quot;&gt;Enhance Interaction with Mouse Wheel Support&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;mousewheel.jpg&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/mousewheel_ZdLdi7.webp&quot; srcset=&quot;/_astro/mousewheel_2evOYG.webp 640w, /_astro/mousewheel_1btqKu.webp 750w, /_astro/mousewheel_Z1mpLwI.webp 828w, /_astro/mousewheel_1aUQbe.webp 1080w, /_astro/mousewheel_t4NVy.webp 1280w, /_astro/mousewheel_ZdLdi7.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In our latest update, our engine now directly registers mouse wheel events on the canvas, eliminating the need for manual camera manipulation. This seamless integration brings a host of new features, including smooth zooming, centered around the cursor, and support for pinch gestures on multitouch trackpads. Enjoy a more intuitive and unified interaction experience across various inputs, simplifying and enriching your design process.&lt;/p&gt;
&lt;h3 id=&quot;migrate-to-cesdk-v119&quot;&gt;Migrate to CE.SDK v1.19&lt;/h3&gt;
&lt;p&gt;The structural changes of CE.SDK v1.19 bring a more composable and powerful editing experience. To benefit from our new features, and to attain to licensing changes, head to our &lt;a href=&quot;https://img.ly/docs/cesdk/js/upgrade-4f8715/&quot;&gt;documentation on migrating to v.1.19&lt;/a&gt; for an easy transition.&lt;/p&gt;
&lt;p&gt;Wait. There’s more. As we explore the extensive capabilities of our SDK, we’re unveiling new showcases to demonstrate your possibilities. Plus, stick around until the end for an exciting announcement that will elevate your video creation experience!&lt;/p&gt;
&lt;h3 id=&quot;new-showcase-automated-resizing&quot;&gt;New Showcase: Automated Resizing&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Scale your marketing materials across all platforms with automated sizes.&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/automated_Z1or62o.webp&quot; srcset=&quot;/_astro/automated_1UVbIY.webp 640w, /_astro/automated_1iPdUS.webp 750w, /_astro/automated_1uk67P.webp 828w, /_astro/automated_DqpQ8.webp 1080w, /_astro/automated_2a5INP.webp 1280w, /_astro/automated_Z1or62o.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In our new live &lt;a href=&quot;https://img.ly/showcases/cesdk/automated-resizing/web&quot;&gt;showcase&lt;/a&gt; for web, effortlessly generate size variations of your designs and seamlessly &lt;strong&gt;scale your&lt;/strong&gt; &lt;strong&gt;marketing materials across platforms&lt;/strong&gt;. The automated resizing feature empowers you to easily leverage marketing materials without requiring the involvement of a design team, ensuring efficiency and adaptability.&lt;/p&gt;
&lt;h3 id=&quot;new-showcase-version-history&quot;&gt;New Showcase: Version History&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Keep track! Version History monitors changes made to your design.&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/history_Z1I9vf0.webp&quot; srcset=&quot;/_astro/history_1suucg.webp 640w, /_astro/history_ZuG7lP.webp 750w, /_astro/history_1T8alE.webp 828w, /_astro/history_Z1gpSmo.webp 1080w, /_astro/history_Z1uhGNc.webp 1280w, /_astro/history_Z1I9vf0.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Discover the convenience of Version History, enabling you to monitor changes made to each design and seamlessly restore past versions when needed. Explore our straightforward &lt;a href=&quot;https://img.ly/showcases/cesdk/version-history/web&quot;&gt;Version History&lt;/a&gt; showcase for a practical design experience.&lt;/p&gt;
&lt;h3 id=&quot;outlook-offer-tiktok-inspired-video-editing&quot;&gt;Outlook: Offer TikTok-Inspired Video Editing&lt;/h3&gt;
&lt;p&gt;Video remains the reigning champion for attracting and retaining your audience. Yet, building a video editor from the ground up is a pain.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-19/HD_IMGLY-SDK_141223-0.mp4&quot; controls playsinline poster=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-19/thumb-vcc.jpg&quot;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;To simplify your journey and save valuable time and resources, we are excited to unveil a groundbreaking SDK for creating captivating short-form videos in January 2024!&lt;/p&gt;
&lt;p&gt;Empower your users to arrange video, audio, text, and graphics seamlessly on a sleek video timeline. Our new camera introduces popular features like Voiceover, Zoom, Tap to Record, and more. Plus, bring the beloved Split Screen Modes for Reactions and Duets, akin to TikTok and Instagram!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://share.hsforms.com/1mrIXiBbURn6sMqYgZG9c6A1hk3i&quot;&gt;Be the first to access our new IMG.LY SDK—join our waitlist now!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thanks for reading!&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 to stay in the loop with the latest news and updates.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Neslihan</dc:creator><media:content url="https://blog.img.ly/2023/12/v119.jpg" medium="image"/><category>Release Notes</category><category>CE.SDK</category><category>Video Editing</category><category>Design Editor</category><category>App Development</category><category>Mobile App Development</category></item><item><title>CE.SDK v1.17 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v_1_17_0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v_1_17_0-release-notes/</guid><description>Discover more about our new WebP Support, Seamless Android Video Capture, and Editing!</description><pubDate>Tue, 17 Oct 2023 12:48:42 GMT</pubDate><content:encoded>&lt;p&gt;In the ever-evolving landscape of app development, staying ahead of the curve is crucial. Since our &lt;a href=&quot;https://img.ly/blog/creative-editor-sdk-v_1_16_0-release-notes/&quot;&gt;last release&lt;/a&gt;, we’ve been crafting new features to empower your users’ creative journey. Today, we’re thrilled to introduce CE.SDK v1.17. With this release, you can:&lt;/p&gt;
&lt;h2 id=&quot;support-webp-file-formats&quot;&gt;Support WebP File Formats&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;webp.jpg&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/webp_ZihMfY.webp&quot; srcset=&quot;/_astro/webp_WMgHq.webp 640w, /_astro/webp_Zktgcw.webp 750w, /_astro/webp_ZaozQq.webp 828w, /_astro/webp_lWaNa.webp 1080w, /_astro/webp_1OGgA.webp 1280w, /_astro/webp_ZihMfY.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Interfaces: Engine&lt;br&gt;
Platforms: All&lt;/p&gt;
&lt;p&gt;We’re delighted to announce that our editor now supports WebP images, delivering you an array of benefits. WebP is gaining popularity for its unique ability to strike the perfect balance between high image quality and smaller file sizes. This means your visuals will look stunning while optimizing website performance.&lt;/p&gt;
&lt;h2 id=&quot;capture-and-export-videos-with-camera-for-android&quot;&gt;&lt;strong&gt;Capture and Export Videos with Camera for Android&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;android-camera-clips.jpg&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/android-camera-1_1QwCnP.webp&quot; srcset=&quot;/_astro/android-camera-1_SXytg.webp 640w, /_astro/android-camera-1_Z1uUni0.webp 750w, /_astro/android-camera-1_1eF16r.webp 828w, /_astro/android-camera-1_Z2hfyrm.webp 1080w, /_astro/android-camera-1_2keARH.webp 1280w, /_astro/android-camera-1_1QwCnP.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Interfaces: Engine&lt;br&gt;
Platforms: Android&lt;/p&gt;
&lt;p&gt;Video content creation has become the lifeblood of today’s app ecosystem. Social entertainment, user-generated content, and the demand for immersive experiences have transformed the way we engage with audiences.&lt;/p&gt;
&lt;p&gt;We’re excited to introduce &lt;strong&gt;Camera Recording for Android&lt;/strong&gt;, seamlessly integrating your live camera preview with our engine’s extensive capabilities. This means you can apply a wide range of effects, strokes, and drop shadows to your live camera feed, all while ensuring it harmoniously blends into the composition of your scene.&lt;/p&gt;
&lt;p&gt;This feature allows you to seamlessly capture, edit, and export high-quality videos directly within your applications. Whether you’re building a social platform, a video editing app, or a storytelling tool, this feature will redefine your users’ video creation experience. Learn how to use your camera in our Engine for Android in our &lt;a href=&quot;https://img.ly/docs/cesdk/android/import-media/capture-from-camera/record-video-47819b/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Stay tuned for more exciting updates and the &lt;strong&gt;full reveal&lt;/strong&gt;: CE.SDK v1.17 is just the beginning of a new era in app-driven video content.&lt;/p&gt;
&lt;p&gt;Thank you for being a part of this journey with us. Subscribe to our &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;newsletter&lt;/a&gt; to ensure you never miss out on updates! &lt;strong&gt;?&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Neslihan</dc:creator><media:content url="https://blog.img.ly/2023/10/white-label-editor-1_17.jpg" medium="image"/><category>Release Notes</category><category>Android</category><category>App Development</category></item><item><title>Elegant Event Handling in Kotlin - A Refactoring Walkthrough</title><link>https://img.ly/blog/kotlin-code-refactoring-for-peak-performance/</link><guid isPermaLink="true">https://img.ly/blog/kotlin-code-refactoring-for-peak-performance/</guid><description>Unlock peak performance in Kotlin code with these expert refactoring tips.</description><pubDate>Fri, 29 Sep 2023 07:00:53 GMT</pubDate><content:encoded>&lt;p&gt;In the world of software development, code refactoring is the hero that rescues us from tangled and inefficient code. In this article, we’ll embark on an adventure to revamp Kotlin code handling diverse events. Our mission? To enhance performance and style, making the code sleeker, more maintainable, and a joy to work with.&lt;/p&gt;
&lt;h2 id=&quot;what-we-aim-to-achieve&quot;&gt;What We Aim to Achieve&lt;/h2&gt;
&lt;p&gt;On this journey to transform Kotlin event handling, our goal is to refine our code to be more efficient, readable, and maintainable. We’re introducing a variety of improvements, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Replacing a convoluted &lt;code&gt;when&lt;/code&gt; statement with a &lt;code&gt;HashMap&lt;/code&gt; for lightning-fast (O(1)) performance.&lt;/li&gt;
&lt;li&gt;Infusing syntactic sweetness with inline functions and &lt;a href=&quot;https://kotlinlang.org/docs/inline-functions.html#reified-type-parameters&quot;&gt;reified&lt;/a&gt; type parameters.&lt;/li&gt;
&lt;li&gt;Employing delegated properties for cleaner dependency injection.&lt;/li&gt;
&lt;li&gt;Adhering to the Single Responsibility Principle by enabling multiple specialized event handler functions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;step-1-the-starting-line&quot;&gt;Step 1: The Starting Line&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;sven2244_a_playful_abstract_artwork_that_represents_the_complex_6e9491ff-8203-4ae2-9a5e-52025e4010be.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1856px) 1856px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1856&quot; height=&quot;656&quot; src=&quot;https://img.ly/_astro/2_1H0FvJ.webp&quot; srcset=&quot;/_astro/2_Z2e3gQ7.webp 640w, /_astro/2_2dHdPv.webp 750w, /_astro/2_ZB5tWb.webp 828w, /_astro/2_Z1Ro7yX.webp 1080w, /_astro/2_Qgvw5.webp 1280w, /_astro/2_NDMYj.webp 1668w, /_astro/2_1H0FvJ.webp 1856w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Our adventure begins with a glance at the original code. This codebase manages a variety of block events through a function named &lt;code&gt;handleBlockEvent&lt;/code&gt; and an event handler function called &lt;code&gt;onEvent&lt;/code&gt;. Let’s unveil the original code:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;open&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onEvent&lt;/span&gt;&lt;span&gt;(event: &lt;/span&gt;&lt;span&gt;Event&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;    handleBlockEvent&lt;/span&gt;&lt;span&gt;(engine, &lt;/span&gt;&lt;span&gt;getBlockForEvents&lt;/span&gt;&lt;span&gt;(), &lt;/span&gt;&lt;span&gt;checkNotNull&lt;/span&gt;&lt;span&gt;(assetsRepo.fontFamilies.&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;getOrThrow&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;fun&lt;/span&gt;&lt;span&gt; handleBlockEvent&lt;/span&gt;&lt;span&gt;(engine: &lt;/span&gt;&lt;span&gt;Engine&lt;/span&gt;&lt;span&gt;, block: &lt;/span&gt;&lt;span&gt;DesignBlock&lt;/span&gt;&lt;span&gt;, fontFamilyMap: &lt;/span&gt;&lt;span&gt;Map&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;FontFamilyData&lt;/span&gt;&lt;span&gt;&gt;, event: &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    when&lt;/span&gt;&lt;span&gt; (event) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        BlockEvent.OnDelete &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; engine.&lt;/span&gt;&lt;span&gt;delete&lt;/span&gt;&lt;span&gt;(block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        BlockEvent.OnBackward &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; engine.&lt;/span&gt;&lt;span&gt;sendBackward&lt;/span&gt;&lt;span&gt;(block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        BlockEvent.OnDuplicate &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; engine.&lt;/span&gt;&lt;span&gt;duplicate&lt;/span&gt;&lt;span&gt;(block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        BlockEvent.OnForward &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; engine.&lt;/span&gt;&lt;span&gt;bringForward&lt;/span&gt;&lt;span&gt;(block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        BlockEvent.ToBack &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; engine.&lt;/span&gt;&lt;span&gt;sendToBack&lt;/span&gt;&lt;span&gt;(block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        BlockEvent.ToFront &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; engine.&lt;/span&gt;&lt;span&gt;bringToFront&lt;/span&gt;&lt;span&gt;(block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        BlockEvent.OnChangeFinish &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; engine.editor.&lt;/span&gt;&lt;span&gt;addUndoStep&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        is&lt;/span&gt;&lt;span&gt; BlockEvent.OnChangeBlendMode &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; onChangeBlendMode&lt;/span&gt;&lt;span&gt;(engine, block, event.blendMode)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        is&lt;/span&gt;&lt;span&gt; BlockEvent.OnChangeOpacity &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;setOpacity&lt;/span&gt;&lt;span&gt;(block, event.opacity)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        is&lt;/span&gt;&lt;span&gt; BlockEvent.OnChangeFillColor &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; onChangeFillColor&lt;/span&gt;&lt;span&gt;(engine, block, event.color)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // and so on...&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;sealed&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; BlockEvent&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;Event&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    object&lt;/span&gt;&lt;span&gt; OnChangeFinish&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    object&lt;/span&gt;&lt;span&gt; OnForward&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    object&lt;/span&gt;&lt;span&gt; OnBackward&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    object&lt;/span&gt;&lt;span&gt; OnDuplicate&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    object&lt;/span&gt;&lt;span&gt; OnDelete&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    object&lt;/span&gt;&lt;span&gt; ToFront&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    object&lt;/span&gt;&lt;span&gt; ToBack&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    data&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; OnChangeBlendMode&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; blendMode: &lt;/span&gt;&lt;span&gt;BlendMode&lt;/span&gt;&lt;span&gt;) : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    data&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; OnChangeOpacity&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; opacity: &lt;/span&gt;&lt;span&gt;Float&lt;/span&gt;&lt;span&gt;) : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    data&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; OnChangeFillColor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; color: &lt;/span&gt;&lt;span&gt;Color&lt;/span&gt;&lt;span&gt;) : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // and so on...&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;To use the original code, you’d typically call the &lt;code&gt;onEvent&lt;/code&gt; function with a specific event:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;onEvent&lt;/span&gt;&lt;span&gt;(BlockEvent.&lt;/span&gt;&lt;span&gt;OnChangeFillColor&lt;/span&gt;&lt;span&gt;(Color.RED))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This would then trigger the &lt;code&gt;handleBlockEvent&lt;/code&gt; function to deal with the event at hand. Now, let’s embark on our first refactoring adventure.&lt;/p&gt;
&lt;h2 id=&quot;step-2-unveiling-hashmaps-and-payloads-for-peak-performance&quot;&gt;Step 2: Unveiling HashMaps and Payloads for Peak Performance&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;sven2244_an_abstract_image_ofa_futuristic_cityscape_with_neon-l_fbda2c5b-b80f-430b-9f00-609ceecc1292.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1856px) 1856px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1856&quot; height=&quot;656&quot; src=&quot;https://img.ly/_astro/3_ZK0M1r.webp&quot; srcset=&quot;/_astro/3_Z2iStzt.webp 640w, /_astro/3_28R179.webp 750w, /_astro/3_ZFUGFx.webp 828w, /_astro/3_JLxGM.webp 1080w, /_astro/3_Z1AJW16.webp 1280w, /_astro/3_Z1DmExR.webp 1668w, /_astro/3_ZK0M1r.webp 1856w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In our first act of refactoring, we introduce a trusty &lt;code&gt;HashMap&lt;/code&gt; to map each event type to its corresponding action. This heroic move eliminates the need for the convoluted &lt;code&gt;when&lt;/code&gt; statement, making our code more efficient. We also unveil a payload mechanism to convey essential data to the event handlers.&lt;/p&gt;
&lt;p&gt;Behold the refactored code:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;abstract&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    val&lt;/span&gt;&lt;span&gt; fillPayload: (&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt;) -&gt; &lt;/span&gt;&lt;span&gt;Unit&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;    abstract&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt; payloadCache: &lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    private&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt; eventMap &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; mutableMapOf&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;KClass&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;out Event&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;, Payloads.(event: &lt;/span&gt;&lt;span&gt;Event&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Unit&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 class=&quot;line&quot;&gt;&lt;span&gt;    fun&lt;/span&gt;&lt;span&gt; handleEvent&lt;/span&gt;&lt;span&gt;(event: &lt;/span&gt;&lt;span&gt;Event&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        eventMap[event::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;]?.&lt;/span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            it.&lt;/span&gt;&lt;span&gt;invoke&lt;/span&gt;&lt;span&gt;(payloadCache.&lt;/span&gt;&lt;span&gt;also&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;fillPayload&lt;/span&gt;&lt;span&gt;(it) }, event)&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;    operator&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;Event&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(event: &lt;/span&gt;&lt;span&gt;KClass&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span&gt; EventType&lt;/span&gt;&lt;span&gt;&gt;, lambda: &lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt;.(event: &lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Unit) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        eventMap[event] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; lambda &lt;/span&gt;&lt;span&gt;as&lt;/span&gt;&lt;span&gt; Payloads.(event: &lt;/span&gt;&lt;span&gt;Event&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Unit&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; BlockEventsHandler&lt;/span&gt;&lt;span&gt;(fillPayload: (&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;BlockEventsHandler&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt;) -&gt; &lt;/span&gt;&lt;span&gt;Unit&lt;/span&gt;&lt;span&gt;) : &lt;/span&gt;&lt;span&gt;EventsHandler&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEventsHandler&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;fillPayload&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    class&lt;/span&gt;&lt;span&gt; Payloads&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        lateinit&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt; engine: &lt;/span&gt;&lt;span&gt;Engine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        lateinit&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt; block: &lt;/span&gt;&lt;span&gt;DesignBlock&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        lateinit&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt; fontFamilyMap: &lt;/span&gt;&lt;span&gt;Map&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;FontFamilyData&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;    override&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt; payloadCache: &lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; Payloads&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;    init&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.OnDelete::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { engine.&lt;/span&gt;&lt;span&gt;delete&lt;/span&gt;&lt;span&gt;(block) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.OnBackward::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { engine.&lt;/span&gt;&lt;span&gt;sendBackward&lt;/span&gt;&lt;span&gt;(block) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.OnDuplicate::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { engine.&lt;/span&gt;&lt;span&gt;duplicate&lt;/span&gt;&lt;span&gt;(block) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.OnForward::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { engine.&lt;/span&gt;&lt;span&gt;bringForward&lt;/span&gt;&lt;span&gt;(block) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.ToBack::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { engine.&lt;/span&gt;&lt;span&gt;sendToBack&lt;/span&gt;&lt;span&gt;(block) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.ToFront::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { engine.&lt;/span&gt;&lt;span&gt;bringToFront&lt;/span&gt;&lt;span&gt;(block) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.OnChangeFinish::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { engine.editor.&lt;/span&gt;&lt;span&gt;addUndoStep&lt;/span&gt;&lt;span&gt;() }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.OnChangeBlendMode::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;onChangeBlendMode&lt;/span&gt;&lt;span&gt;(engine, block, it.blendMode) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.OnChangeOpacity::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { engine.block.&lt;/span&gt;&lt;span&gt;setOpacity&lt;/span&gt;&lt;span&gt;(block, it.opacity) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.OnChangeFillColor::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;onChangeFillColor&lt;/span&gt;&lt;span&gt;(engine, block, it.color) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // and so on...&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;private&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt; blockEventHandler &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; BlockEventsHandler&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    it.engine &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; engine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    it.block &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; getBlockForEvents&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    it.fontFamilyMap &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; checkNotNull&lt;/span&gt;&lt;span&gt;(assetsRepo.fontFamilies.&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;getOrThrow&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;open&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onEvent&lt;/span&gt;&lt;span&gt;(event: &lt;/span&gt;&lt;span&gt;Event&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;    blockEventHandler.&lt;/span&gt;&lt;span&gt;handleEvent&lt;/span&gt;&lt;span&gt;(event)&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;a-performance-boost&quot;&gt;A Performance Boost&lt;/h3&gt;
&lt;p&gt;By harnessing the power of a &lt;code&gt;HashMap&lt;/code&gt;, we’ve turbocharged our event handling. The time complexity for handling an event is now a lightning-fast (O(1)), a monumental improvement over the (O(n)) time complexity of the ponderous &lt;code&gt;when&lt;/code&gt; statement. While our payload mechanism adds a dollop of syntactic sugar. It enables us to bundle all the necessary data into a single object, making our code more legible and maintainable.&lt;/p&gt;
&lt;p&gt;? Note: Using a HashMap instead of a large when() statement provides a significant performance improvement. It can be up to 40 to 150 times faster. However, explaining the details would exceed the scope of this blog post. Therefore, I will cover it, along with other Kotlin performance puzzles, in a future blog post.&lt;/p&gt;
&lt;p&gt;While the refactored code remains as simple as before:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;onEvent&lt;/span&gt;&lt;span&gt;(BlockEvent.&lt;/span&gt;&lt;span&gt;OnChangeFillColor&lt;/span&gt;&lt;span&gt;(Color.RED))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This still triggers the &lt;code&gt;handleEvent&lt;/code&gt; method in &lt;code&gt;BlockEventsHandler&lt;/code&gt;, which in turn performs the appropriate action based on the event type. The &lt;code&gt;BlockEvent&lt;/code&gt; itself is a data object containing all event details, and it serves as the lambda parameter.&lt;/p&gt;
&lt;h3 id=&quot;a-note-on-payloads&quot;&gt;A Note on Payloads&lt;/h3&gt;
&lt;p&gt;The payload creation is a dynamic lambda function that’s executed each time an event is handled. This ensures that all variables not part of the event are consistently up-to-date. Given that we’re dealing with a single thread per event handler, caching the payload is entirely secure.&lt;/p&gt;
&lt;h2 id=&quot;step-3-adding-syntactic-sweetness-with-infix-functions&quot;&gt;Step 3: Adding Syntactic Sweetness with Infix Functions&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;sven2244_an_abstract_composition_resembling_a_candy_store_fille_894e8c68-0a37-4ad0-adc8-c313db1c29da.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1856px) 1856px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1856&quot; height=&quot;656&quot; src=&quot;https://img.ly/_astro/4_1R9Sfj.webp&quot; srcset=&quot;/_astro/4_Z2nIGiP.webp 640w, /_astro/4_241NnM.webp 750w, /_astro/4_ZKKToT.webp 828w, /_astro/4_Z1HeTPo.webp 1080w, /_astro/4_11pIfE.webp 1280w, /_astro/4_XN0HS.webp 1668w, /_astro/4_1R9Sfj.webp 1856w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In our next act, we elevate our syntax to a new level of expressiveness and readability. We introduce an infix function called &lt;code&gt;to&lt;/code&gt;, allowing us to map an event class to its corresponding action elegantly.&lt;/p&gt;
&lt;p&gt;Witness the updated code:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;abstract&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    val&lt;/span&gt;&lt;span&gt; fillPayload: (&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt;) -&gt; &lt;/span&gt;&lt;span&gt;Unit&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;    infix&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;Event&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;KClass&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;out EventType&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;(lambda: &lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt;.(event: &lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Unit) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        eventMap[event] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; lambda &lt;/span&gt;&lt;span&gt;as&lt;/span&gt;&lt;span&gt; Payloads.(event: &lt;/span&gt;&lt;span&gt;Event&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Unit&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;    // ... (rest of the code remains the same)&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; BlockEventsHandler&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    manager: &lt;/span&gt;&lt;span&gt;EventsManager&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    override&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt; fillPayload: (&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;TextBlockEventsHandler&lt;/span&gt;&lt;span&gt;) -&gt; &lt;/span&gt;&lt;span&gt;Unit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;) : &lt;/span&gt;&lt;span&gt;EventsHandler&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;TextBlockEventsHandler&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;manager&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    lateinit&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt; engine: &lt;/span&gt;&lt;span&gt;Engine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    lateinit&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt; block: &lt;/span&gt;&lt;span&gt;DesignBlock&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    lateinit&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt; fontFamilyMap: &lt;/span&gt;&lt;span&gt;Map&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;FontFamilyData&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;    init&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        BlockEvent.OnDelete::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.&lt;/span&gt;&lt;span&gt;delete&lt;/span&gt;&lt;span&gt;(block)&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;        BlockEvent.OnBackward::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.&lt;/span&gt;&lt;span&gt;sendBackward&lt;/span&gt;&lt;span&gt;(block)&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;        BlockEvent.OnDuplicate::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.&lt;/span&gt;&lt;span&gt;duplicate&lt;/span&gt;&lt;span&gt;(block)&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;        BlockEvent.OnForward::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.&lt;/span&gt;&lt;span&gt;bringForward&lt;/span&gt;&lt;span&gt;(block)&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;        BlockEvent.ToBack::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.&lt;/span&gt;&lt;span&gt;sendToBack&lt;/span&gt;&lt;span&gt;(block)&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;        BlockEvent.ToFront::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.&lt;/span&gt;&lt;span&gt;bringToFront&lt;/span&gt;&lt;span&gt;(block)&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;        BlockEvent.OnChangeFinish::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.editor.&lt;/span&gt;&lt;span&gt;addUndoStep&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;        BlockEvent.OnChangeBlendMode::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onChangeBlendMode&lt;/span&gt;&lt;span&gt;(engine, block, it.blendMode)&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;        BlockEvent.OnChangeOpacity::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&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;setOpacity&lt;/span&gt;&lt;span&gt;(block, it.opacity)&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;        BlockEvent.OnChangeFillColor::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onChangeFillColor&lt;/span&gt;&lt;span&gt;(engine, block, it.color)&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;syntactic-sweetness-and-performance&quot;&gt;Syntactic Sweetness and Performance&lt;/h3&gt;
&lt;p&gt;The introduction of the &lt;code&gt;to&lt;/code&gt; infix function adds a sprinkle of syntactic sweetness that enhances code expressiveness and enables a more natural usage. This makes it crystal clear what each event is all about. And fear not, the performance remains at a blazing-fast (O(1)), thanks to our trusty HashMap.&lt;/p&gt;
&lt;h3 id=&quot;flexibility-in-syntax&quot;&gt;Flexibility in Syntax&lt;/h3&gt;
&lt;p&gt;While the &lt;code&gt;to&lt;/code&gt; keyword is used here, feel free to substitute it with other terms like &lt;code&gt;handle&lt;/code&gt;, &lt;code&gt;trigger&lt;/code&gt;, or anything that best suits your context. Flexibility is the name of the game.&lt;/p&gt;
&lt;h2 id=&quot;step-4-embracing-inline-functions-for-elegance&quot;&gt;Step 4: Embracing Inline Functions for Elegance&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;sven2244_a_mesmerizing_image_of_a_kaleidoscope_with_vibrant_pat_b53a7e30-820a-4308-a7aa-11222be8a7a1.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1856px) 1856px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1856&quot; height=&quot;656&quot; src=&quot;https://img.ly/_astro/5_ZzQzhR.webp&quot; srcset=&quot;/_astro/5_Z2syT2c.webp 640w, /_astro/5_1YbAEq.webp 750w, /_astro/5_ZPB78g.webp 828w, /_astro/5_TUKqm.webp 1080w, /_astro/5_Z1qAJhw.webp 1280w, /_astro/5_Z1tdrOi.webp 1668w, /_astro/5_ZzQzhR.webp 1856w&quot;&gt;&lt;/p&gt;
&lt;p&gt;However, this is still not perfect because the &lt;code&gt;::class&lt;/code&gt; breaks smooth reading.&lt;/p&gt;
&lt;p&gt;So let’s do it differently. Let us try to introduce a more elegant way to register an event. Let us eliminate the need to specify &lt;code&gt;::class&lt;/code&gt; every time we register an event handler will make our code more concise and readable.&lt;/p&gt;
&lt;p&gt;This is made possible by an inline function with a verified type parameter that maintains the class reference at runtime.&lt;/p&gt;
&lt;p&gt;To do this, we extend the &lt;code&gt;EventsHandler&lt;/code&gt; class with this new &lt;code&gt;register&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    register: &lt;/span&gt;&lt;span&gt;EventsHandler&lt;/span&gt;&lt;span&gt;.() &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Unit,&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;    inline&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;reified&lt;/span&gt;&lt;span&gt; EventType&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BaseEvent&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;register&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;noinline&lt;/span&gt;&lt;span&gt; lambda: (&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;) -&gt; &lt;/span&gt;&lt;span&gt;Unit&lt;/span&gt;&lt;span&gt;) : &lt;/span&gt;&lt;span&gt;Any&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;[EventType::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; lambda&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        return&lt;/span&gt;&lt;span&gt; lambda&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;   // ... (rest of the code remains the same)&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;the-new-syntax&quot;&gt;The New Syntax&lt;/h3&gt;
&lt;p&gt;This is what registering an event handler looks like with the new syntax:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OnChangeLineWidth&lt;/span&gt;&lt;span&gt;&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;setWidth&lt;/span&gt;&lt;span&gt;(block, engine.block.&lt;/span&gt;&lt;span&gt;getFrameWidth&lt;/span&gt;&lt;span&gt;(block))&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;(block, it.width)&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;Much better, right? The new syntax is more concise, eliminates redundancy, and is type-safe because the reified type parameters ensure that the event type is known at compile-time and runtime, eliminating the need for unsafe casting.&lt;/p&gt;
&lt;h2 id=&quot;step-5-elevating-register-to-an-extension-function-for-highlighting&quot;&gt;Step 5: Elevating &lt;code&gt;register&lt;/code&gt; to an Extension Function for Highlighting&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;highlighting.jpg&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;700&quot; src=&quot;https://img.ly/_astro/6-1_ZpUYI8.webp&quot; srcset=&quot;/_astro/6-1_1WCnM8.webp 640w, /_astro/6-1_Z2lJRV7.webp 750w, /_astro/6-1_1HMAQd.webp 828w, /_astro/6-1_ZlU4Yo.webp 1080w, /_astro/6-1_Z2ruRRK.webp 1280w, /_astro/6-1_Z29YNlp.webp 1668w, /_astro/6-1_ZpUYI8.webp 2000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;To improve code readability, we’ll make a subtle but effective step by converting the &lt;code&gt;register&lt;/code&gt; function from a &lt;code&gt;EventsHandler&lt;/code&gt; class function, into an &lt;code&gt;EventsHandler&lt;/code&gt; extension function.&lt;/p&gt;
&lt;p&gt;Sounds stupid! So why?&lt;/p&gt;
&lt;p&gt;This small change improves code readability by highlighting the &lt;code&gt;register&lt;/code&gt; keyword through syntax highlighting from a Kotlin extension function. This will make it much more colorful, which improves readability.&lt;/p&gt;
&lt;h3 id=&quot;updated-eventshandler-class&quot;&gt;Updated &lt;code&gt;EventsHandler&lt;/code&gt; Class&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;EventsHandler&lt;/code&gt; class remains largely unchanged, but the &lt;code&gt;register&lt;/code&gt; function is now outside the class and transformed into an extension function for the &lt;code&gt;EventsHandler&lt;/code&gt; class:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    register: &lt;/span&gt;&lt;span&gt;EventsHandler&lt;/span&gt;&lt;span&gt;.() &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Unit,&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;    // ... (rest of the code remains the same)&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;inline&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;reified&lt;/span&gt;&lt;span&gt; EventType&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BaseEvent&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;EventsHandler&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;register&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;noinline&lt;/span&gt;&lt;span&gt; lambda: (&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;) -&gt; &lt;/span&gt;&lt;span&gt;Unit&lt;/span&gt;&lt;span&gt;) : &lt;/span&gt;&lt;span&gt;Any&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;[EventType::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; lambda&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; lambda&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;By simply shifting &lt;code&gt;register&lt;/code&gt; out of the class, the &lt;code&gt;EventsHandler&lt;/code&gt; class definition now stands out with distinctive syntax highlighting. It’s a clever trick that doesn’t impact runtime or compile performance, since it’s an inline operation anyway.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;**&lt;/span&gt;&lt;span&gt;register&lt;/span&gt;&lt;span&gt;**&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent.OnChangeLineWidth&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;    engine.block.&lt;/span&gt;&lt;span&gt;setWidth&lt;/span&gt;&lt;span&gt;(block, engine.block.&lt;/span&gt;&lt;span&gt;getFrameWidth&lt;/span&gt;&lt;span&gt;(block))&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;(block, it.width)&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-6-eliminating-lateinit-variables-with-delegated-properties&quot;&gt;Step 6: Eliminating &lt;code&gt;lateinit&lt;/code&gt; Variables with Delegated Properties&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;sven2244_an_abstract_image_of_interconnected_gears_and_cogs_for_3b651ffc-9367-470d-8be3-82c3c19b9ffe.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1856px) 1856px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1856&quot; height=&quot;656&quot; src=&quot;https://img.ly/_astro/7_ZpHmyi.webp&quot; srcset=&quot;/_astro/7_2rVOk1.webp 640w, /_astro/7_1OvbcH.webp 750w, /_astro/7_Z10hwzY.webp 828w, /_astro/7_154X9V.webp 1080w, /_astro/7_Z1grwxW.webp 1280w, /_astro/7_Z1j4f5I.webp 1668w, /_astro/7_ZpHmyi.webp 1856w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now, it’s time to address the enigmatic &lt;code&gt;lateinit&lt;/code&gt; variables and the somewhat convoluted &lt;code&gt;fillPayload&lt;/code&gt; mechanism. Let us introduce a cleaner approach, using delegated properties and lambda functions to inject dependencies.&lt;/p&gt;
&lt;p&gt;Let’s add an &lt;code&gt;Inject&lt;/code&gt; class to wrap a normal lambda as delegable:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Type&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt; inject: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Type) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    operator&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; getValue&lt;/span&gt;&lt;span&gt;(thisRef: &lt;/span&gt;&lt;span&gt;Any&lt;/span&gt;&lt;span&gt;?, property: &lt;/span&gt;&lt;span&gt;KProperty&lt;/span&gt;&lt;span&gt;&amp;#x3C;*&gt;): &lt;/span&gt;&lt;span&gt;Type&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; inject&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;With this newfound power, our event handler code becomes cleaner and more intuitive. It takes on the style of Jetpack Compose’s declarative syntax:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;textBlockEvents&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    engine: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Engine,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    block: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; DesignBlock,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    fontFamilyMap: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Map&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String, FontFamilyData&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;    // Inject the dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    val&lt;/span&gt;&lt;span&gt; engine &lt;/span&gt;&lt;span&gt;by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(engine)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    val&lt;/span&gt;&lt;span&gt; block &lt;/span&gt;&lt;span&gt;by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    val&lt;/span&gt;&lt;span&gt; fontFamilyMap &lt;/span&gt;&lt;span&gt;by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(fontFamilyMap)&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;    // Event handling logic here&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;Whenever one of the variables is accessed, the lambda is called, and you always get the current variable.&lt;/p&gt;
&lt;p&gt;Also, the creation of the “payload” becomes more straightforward, clean, and type-safe. It kinda looks like passing a variable:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt; eventHandler &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    textBlockEvents&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        engine &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ::&lt;/span&gt;&lt;span&gt;engine&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        block &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ::&lt;/span&gt;&lt;span&gt;getBlockForEvents&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        fontFamilyMap &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;checkNotNull&lt;/span&gt;&lt;span&gt;(assetsRepo.fontFamilies.&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;getOrThrow&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;Looks and feels like magic! Pretty cool, right?&lt;/p&gt;
&lt;h2 id=&quot;step-7-multiple-event-handlers-for-single-responsibility-principle&quot;&gt;Step 7: Multiple Event Handlers for Single Responsibility Principle&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;sven2244_code_as_a_magical_candy-filled_wonderland._Syntax_Suga_a50bcd92-bea2-4fea-aa92-e1cd557277b6.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1856px) 1856px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1856&quot; height=&quot;656&quot; src=&quot;https://img.ly/_astro/8_2csiHs.webp&quot; srcset=&quot;/_astro/8_2n6BAE.webp 640w, /_astro/8_1JEXtl.webp 750w, /_astro/8_Z157Jjl.webp 828w, /_astro/8_Z1mVunf.webp 1080w, /_astro/8_1lI8HN.webp 1280w, /_astro/8_1j6qb2.webp 1668w, /_astro/8_2csiHs.webp 1856w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In our grand finale, we harness the newfound flexibility from our previous changes to register multiple event handler functions. Each event handler registration function now has a specific topic, aligning perfectly with the Single Responsibility Principle (SRP).&lt;/p&gt;
&lt;h3 id=&quot;enhanced-event-handler-registration&quot;&gt;Enhanced Event Handler Registration&lt;/h3&gt;
&lt;p&gt;We can now register multiple event handler functions within the same &lt;code&gt;EventsHandler&lt;/code&gt; instance. Each function can specialize in handling a particular type of event, making the code more modular and manageable. Behold the grand design:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt; eventHandler &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    cropEvents&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        engine &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ::&lt;/span&gt;&lt;span&gt;engine&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        block &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ::&lt;/span&gt;&lt;span&gt;getBlockForEvents&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;    blockEvents&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        engine &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ::&lt;/span&gt;&lt;span&gt;engine&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        block &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ::&lt;/span&gt;&lt;span&gt;getBlockForEvents&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;    textBlockEvents&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        engine &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ::&lt;/span&gt;&lt;span&gt;engine&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        block &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ::&lt;/span&gt;&lt;span&gt;getBlockForEvents&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        fontFamilyMap &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;checkNotNull&lt;/span&gt;&lt;span&gt;(assetsRepo.fontFamilies.&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;getOrThrow&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;fun&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;blockEvents&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    engine: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Engine,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    block: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; DesignBlock&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;    val&lt;/span&gt;&lt;span&gt; engine: &lt;/span&gt;&lt;span&gt;Engine&lt;/span&gt;&lt;span&gt; by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;engine&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    val&lt;/span&gt;&lt;span&gt; block: &lt;/span&gt;&lt;span&gt;DesignBlock&lt;/span&gt;&lt;span&gt; by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;block&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;    register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OnDelete&lt;/span&gt;&lt;span&gt;&gt; { engine.&lt;/span&gt;&lt;span&gt;delete&lt;/span&gt;&lt;span&gt;(block) }&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;    register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OnBackward&lt;/span&gt;&lt;span&gt;&gt; { engine.&lt;/span&gt;&lt;span&gt;sendBackward&lt;/span&gt;&lt;span&gt;(block) }&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;    register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OnDuplicate&lt;/span&gt;&lt;span&gt;&gt; { engine.&lt;/span&gt;&lt;span&gt;duplicate&lt;/span&gt;&lt;span&gt;(block) }&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;    register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OnForward&lt;/span&gt;&lt;span&gt;&gt; { engine.&lt;/span&gt;&lt;span&gt;bringForward&lt;/span&gt;&lt;span&gt;(block) }&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;    register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ToBack&lt;/span&gt;&lt;span&gt;&gt; { engine.&lt;/span&gt;&lt;span&gt;sendToBack&lt;/span&gt;&lt;span&gt;(block) }&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;    register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ToFront&lt;/span&gt;&lt;span&gt;&gt; { engine.&lt;/span&gt;&lt;span&gt;bringToFront&lt;/span&gt;&lt;span&gt;(block) }&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;    register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OnChangeFinish&lt;/span&gt;&lt;span&gt;&gt; { engine.editor.&lt;/span&gt;&lt;span&gt;addUndoStep&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;    register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OnChangeBlendMode&lt;/span&gt;&lt;span&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        if&lt;/span&gt;&lt;span&gt; (engine.block.&lt;/span&gt;&lt;span&gt;getBlendMode&lt;/span&gt;&lt;span&gt;(block) &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; it.blendMode) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.block.&lt;/span&gt;&lt;span&gt;setBlendMode&lt;/span&gt;&lt;span&gt;(block, it.blendMode)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.editor.&lt;/span&gt;&lt;span&gt;addUndoStep&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;    register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OnChangeOpacity&lt;/span&gt;&lt;span&gt;&gt; { engine.block.&lt;/span&gt;&lt;span&gt;setOpacity&lt;/span&gt;&lt;span&gt;(block, it.opacity) }&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;fun&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cropEvents&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    engine: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Engine,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    block: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; DesignBlock&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;    val&lt;/span&gt;&lt;span&gt; engine: &lt;/span&gt;&lt;span&gt;Engine&lt;/span&gt;&lt;span&gt; by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;engine&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    val&lt;/span&gt;&lt;span&gt; block: &lt;/span&gt;&lt;span&gt;DesignBlock&lt;/span&gt;&lt;span&gt; by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;block&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // ... (event handling logic for cropping events)&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;fun&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;textBlockEvents&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    engine: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Engine,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    block: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; DesignBlock,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    fontFamilyMap: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Map&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String, FontFamilyData&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;    val&lt;/span&gt;&lt;span&gt; engine &lt;/span&gt;&lt;span&gt;by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(engine)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    val&lt;/span&gt;&lt;span&gt; block &lt;/span&gt;&lt;span&gt;by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    val&lt;/span&gt;&lt;span&gt; fontFamilyMap &lt;/span&gt;&lt;span&gt;by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(fontFamilyMap)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // ... (event handling logic for text block events)&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;While the triggering and its API remain unchanged, and no extra parameters need to be passed:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;open&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onEvent&lt;/span&gt;&lt;span&gt;(event: &lt;/span&gt;&lt;span&gt;Event&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    eventHandler.&lt;/span&gt;&lt;span&gt;handleEvent&lt;/span&gt;&lt;span&gt;(event)&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;final-words&quot;&gt;Final Words&lt;/h2&gt;
&lt;p&gt;As we conclude our journey through Kotlin code refactoring, we’ve unlocked the secrets to enhanced performance and style. By embracing techniques such as HashMaps, infix functions, and inline functions with reified type parameters, we’ve elevated our code to new heights. The benefits are clear: improved efficiency, readability, and adherence to the Single Responsibility Principle. Armed with these tools, you’re now ready to embark on your own coding adventures, transforming messy code into elegant masterpieces.&lt;/p&gt;
&lt;p&gt;If you’d like to try it out, I’ve created a working &lt;a href=&quot;https://pl.kotl.in/tEDorvc04&quot;&gt;example code on the Kotlin Playground&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thank you for accompanying, and happy coding!&lt;/strong&gt; &lt;strong&gt;Never miss out on updates and &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;subscribe&lt;/a&gt; to our newsletter.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Sven</dc:creator><media:content url="https://blog.img.ly/2023/09/hero_01.jpg" medium="image"/><category>How-To</category><category>Android</category><category>Android App Development</category><category>Kotlin</category><category>Insights</category></item><item><title>CE.SDK v1.16 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v_1_16_0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v_1_16_0-release-notes/</guid><description>Keep it colorful! This release brings CMYK and color library support. We also enhanced web touch gestures. Find out more.</description><pubDate>Tue, 26 Sep 2023 14:26:37 GMT</pubDate><content:encoded>&lt;p&gt;It’s getting colorful! Since &lt;a href=&quot;https://img.ly/blog/creative-editor-sdk-v_1_15_0-release-notes/&quot;&gt;our last release&lt;/a&gt;, we’ve been busy crafting new features and enhancements to empower your user’s creative journey. We are excited to announce that CE.SDK v1.16 is now available.&lt;/p&gt;
&lt;p&gt;With this release, you can:&lt;/p&gt;
&lt;h2 id=&quot;maintain-color-consistency-with-cmyk--libraries&quot;&gt;Maintain Color Consistency with CMYK &amp;#x26; Libraries&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Interfaces:&lt;/strong&gt; Engine, Editor&lt;br&gt;
&lt;strong&gt;Platforms:&lt;/strong&gt; Web&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-16/color-cmyk-pantone-naptone.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;We understand the importance of precise color reproduction and the need for brand consistency. That’s why we’re enhancing your editing experience with greater color control.&lt;/p&gt;
&lt;p&gt;You can now seamlessly integrate &lt;strong&gt;CMYK and Pantone color spaces,&lt;/strong&gt; along with other customized color libraries, including &lt;strong&gt;your brand’s unique colors&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This ensures that your designs not only meet but exceed expectations across all mediums, delivering a consistent and visually engaging experience. It also helps eliminate color inconsistencies and product returns, while ensuring color accuracy.&lt;/p&gt;
&lt;p&gt;Learn more about adding color libraries to CE.SDK in our &lt;a href=&quot;https://img.ly/docs/cesdk/js/colors/create-color-palette-7012e0/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;improve-web-interaction-with-touch-gestures&quot;&gt;Improve Web Interaction with Touch Gestures&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Offer enhanced cross-device editor interaction, including multitouch gestures like pinching and zooming.&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-gestures-multitouch_ZmKIw4.webp&quot; srcset=&quot;/_astro/web-gestures-multitouch_Qxp6d.webp 640w, /_astro/web-gestures-multitouch_iwaoR.webp 750w, /_astro/web-gestures-multitouch_15RP4N.webp 828w, /_astro/web-gestures-multitouch_2aoYLz.webp 1080w, /_astro/web-gestures-multitouch_Z1DgVhd.webp 1280w, /_astro/web-gestures-multitouch_ZmKIw4.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interfaces:&lt;/strong&gt; Engine, Editor&lt;br&gt;
&lt;strong&gt;Platforms:&lt;/strong&gt; Web&lt;/p&gt;
&lt;p&gt;With this update, we’re bringing a more interactive and responsive experience to our web applications. Let your users experience seamless &lt;strong&gt;multitouch interactions&lt;/strong&gt;, even on mobile web. This ensures that the content and functionality of our web applications remain accessible and user-friendly across various devices.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thank you for reading! Never miss out on updates 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>Neslihan</dc:creator><media:content url="https://blog.img.ly/2023/10/1-16.jpg" medium="image"/><category>Release Notes</category><category>Creative Editing</category><category>CMYK</category><category>Print</category><category>Design Editor</category><category>Cross-Platform</category><category>App Development</category></item><item><title>CE.SDK v1.14 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v_1_14_0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v_1_14_0-release-notes/</guid><description>Experience faster thumbnails for video, enhanced placeholders, macOS support, and more! </description><pubDate>Fri, 25 Aug 2023 15:37:00 GMT</pubDate><content:encoded>&lt;p&gt;Since &lt;a href=&quot;https://img.ly/blog/creative-editor-sdk-v_1_13_0-release-notes/&quot;&gt;our last release&lt;/a&gt;, we’ve been hard at work developing new features and improvements to enhance your creative editing experience. We are excited to announce that CE.SDK v1.14 is now available!&lt;/p&gt;
&lt;p&gt;With this release, you can:&lt;/p&gt;
&lt;h2 id=&quot;generate-thumbnails-fast-for-smooth-performance&quot;&gt;Generate Thumbnails Fast for Smooth Performance&lt;/h2&gt;
&lt;p&gt;Interfaces: Engine&lt;br&gt;
Platforms: All&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-14/thumbnail-improved.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;We have made significant enhancements to the way video thumbnails are generated, resulting in a smoother and more efficient workflow. Our intelligent engine now renders thumbnails seamlessly across multiple frames, ensuring there are no delays or interruptions while you work. Instead of slow JPEG compression, we have implemented a faster method using raw pixel buffers that maintain high-quality results.&lt;/p&gt;
&lt;p&gt;If you’re using web applications, the thumbnail width adapts to fit your screen, providing a seamless and enjoyable user experience. Additionally, our dynamic thumbnail generation adjusts based on the size of your clips and zoom level, optimizing resources and improving overall performance.&lt;/p&gt;
&lt;h2 id=&quot;enhance-templating-with-improved-placeholders&quot;&gt;Enhance Templating with Improved Placeholders&lt;/h2&gt;
&lt;p&gt;Interfaces: Engine, Editor&lt;br&gt;
Platforms: All&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/placeholder-images.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Introducing an enhanced placeholder behavior for text and image content, allowing for seamless editing and replacement. With the new &lt;code&gt;PlaceholderBehavior&lt;/code&gt; concept, you can define whether a block should initially look and behave as a placeholder or allow editing/replacement. This feature provides a smooth editing experience for users and offers flexibility for template designers to differentiate between placeholder and desired content.&lt;/p&gt;
&lt;h2 id=&quot;bring-creative-editing-to-your-macos-app&quot;&gt;Bring Creative Editing to Your macOS App&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Bring creative editing to your macOS app 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/macOS_Z2iunHV.webp&quot; srcset=&quot;/_astro/macOS_2uXTJb.webp 640w, /_astro/macOS_Rmfii.webp 750w, /_astro/macOS_Z2okYll.webp 828w, /_astro/macOS_1QoMw8.webp 1080w, /_astro/macOS_Zdxi5T.webp 1280w, /_astro/macOS_Z2iunHV.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We’re excited to announce the addition of macOS platform support to our lineup. Extend your application’s reach to macOS users and provide a seamless editing experience across different platforms. Get started, and &lt;strong&gt;initialize our engine in your macOS app&lt;/strong&gt; with our &lt;a href=&quot;https://img.ly/docs/cesdk/macos/overview-8cc730/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;expand-editing-capabilities-macos--catalyst-binding&quot;&gt;Expand Editing Capabilities: macOS &amp;#x26; Catalyst Binding&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Initialize CE.SDK&amp;#39;s engine in your iOS app, and bring creative editing to your users.&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/catalyst_Z1zzDyb.webp&quot; srcset=&quot;/_astro/catalyst_Z16zs6Q.webp 640w, /_astro/catalyst_1SieDm.webp 750w, /_astro/catalyst_20b6IL.webp 828w, /_astro/catalyst_1izTD3.webp 1080w, /_astro/catalyst_2oAGVT.webp 1280w, /_astro/catalyst_Z1zzDyb.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;With this new feature, we provide a comprehensive solution for developers looking to enhance their iOS applications with our CE.SDK’s editing capabilities. Learn how to initialize our creative engine in your iOS app in our &lt;a href=&quot;https://img.ly/docs/cesdk/mac-catalyst/overview-8cc730/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thank you for reading! Never miss out on updates 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>Neslihan</dc:creator><media:content url="https://blog.img.ly/2023/09/ce-sdk_1-14-2.jpg" medium="image"/><category>Release Notes</category><category>Video Editing</category><category>Creative Editor</category><category>CE.SDK</category><category>macOS</category><category>App Development</category></item><item><title>IMG.LY Announces Open Source JavaScript Library for In-Browser Background Removal</title><link>https://img.ly/blog/announcing-imgly-background-removal/</link><guid isPermaLink="true">https://img.ly/blog/announcing-imgly-background-removal/</guid><description>Seamlessly remove backgrounds in-browser with ease. Empower your creativity and protect data privacy. Learn how!</description><pubDate>Wed, 28 Jun 2023 11:38:49 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;UPDATE October 2023&lt;/strong&gt;: We’ve recently introduced Node.js support for the &lt;a href=&quot;https://www.npmjs.com/package/@imgly/background-removal&quot;&gt;@imgly/background-removal&lt;/a&gt; npm package. This enhancement enables you to remove backgrounds from images not only in the user’s browser but also on your server. This opens up the potential for batch processing and allows you to bypass memory constraints, especially for larger images.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Just before the summer lull engulfs us all, we have something exciting to share! We are thrilled to announce the release of &lt;a href=&quot;https://www.npmjs.com/package/@imgly/background-removal&quot;&gt;@imgly/background-removal&lt;/a&gt;, an innovative npm package that empowers developers to seamlessly remove backgrounds from images directly in the browser.&lt;/p&gt;
&lt;p&gt;Gone are the days of relying on server-side processing or sacrificing data privacy. With IMG.LY’s Background Removal, you can now harness the power of in-browser background removal with ease. Let’s dive into the key features that make this library truly exceptional:&lt;/p&gt;
&lt;h3 id=&quot;in-browser-background-removal&quot;&gt;In-Browser Background Removal&lt;/h3&gt;
&lt;p&gt;Our one-of-a-kind solution performs the entire background removal process directly in the user’s browser, eliminating the need for additional server costs. By leveraging the computing power of the local device, users can enjoy a fast and efficient background removal process that streamlines their workflow.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/bg-removal-javascript-open-source.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;data-protection&quot;&gt;Data Protection&lt;/h3&gt;
&lt;p&gt;Rest assured that your images and sensitive information remain secure within your own devices. As IMG.LY’s Background Removal runs entirely in the browser, there are no data transfers to external servers, ensuring robust data privacy and alleviating any concerns you may have.&lt;/p&gt;
&lt;p&gt;You can experience it in action on our &lt;a href=&quot;https://img.ly/showcases/cesdk/web/background-removal/web&quot;&gt;background removal showcase&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;seamless-integration-with-imglys-cesdk&quot;&gt;Seamless Integration with IMG.LY’s CE.SDK&lt;/h3&gt;
&lt;p&gt;IMG.LY’s Background Removal seamlessly integrates with IMG.LY’s CE.SDK, making it easier than ever to incorporate powerful in-browser image matting and background removal capabilities into your projects. Boost your creative endeavors with this intuitive integration.&lt;/p&gt;
&lt;p&gt;The Neural Network (ONNX model) and WebAssembly (WASM) files used by IMG.LY’s Background Removal are hosted on UNPKG, making them readily available for download to all users of the library. However, if you prefer to host the data on your own servers, our library also supports custom asset serving. The choice is yours!&lt;/p&gt;
&lt;p&gt;Background removal is often the first step in any creative workflow involving image composition. Whether you are developing e-commerce applications that need real-time background removal, enhancing user experience in image editing applications, or simplifying the creative process with web-based graphic design tools, IMG.LY’s Background Removal is your go-to solution.&lt;/p&gt;
&lt;h3 id=&quot;empower-yourself-with-imglys-background-removal&quot;&gt;Empower Yourself with IMG.LY’s Background Removal&lt;/h3&gt;
&lt;p&gt;Whether you are a professional developer or a hobbyist, this open source JavaScript library empowers you to deliver impressive applications and services with ease. Join the growing community of developers who are revolutionizing the way background removal is done.&lt;/p&gt;
&lt;p&gt;Get started with @imgly/background-removal today by visiting &lt;a href=&quot;https://www.npmjs.com/package/@imgly/background-removal&quot;&gt;our official npm package page&lt;/a&gt; and &lt;a href=&quot;https://github.com/imgly/background-removal-js/&quot;&gt;our GitHub repository&lt;/a&gt;. You’ll find comprehensive documentation, examples, and everything you need to unlock the full potential of in-browser background removal.&lt;/p&gt;
&lt;h3 id=&quot;update-nodejs-support&quot;&gt;Update: Node.js Support&lt;/h3&gt;
&lt;p&gt;We have just shipped &lt;a href=&quot;https://www.npmjs.com/package/@imgly/background-removal-node&quot;&gt;Node.js support&lt;/a&gt; for the &lt;a href=&quot;https://www.npmjs.com/package/@imgly/background-removal&quot;&gt;@imgly/background-removal&lt;/a&gt; npm package. In addition to the users’ browser, you can now remove backgrounds from images on your server, making it possible to perform batch processing or bypass memory constraints for larger images.&lt;/p&gt;
&lt;p&gt;Thank you for your support, and we can’t wait to see the incredible projects you’ll create with IMG.LY’s Background Removal. Stay tuned for more updates and enhancements as we continue to improve and expand this powerful library. Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Don’t forget to &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;subscribe&lt;/a&gt; to our newsletter to stay in the loop with the latest news and updates.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Jan</dc:creator><media:content url="https://blog.img.ly/2023/06/bg-removal.jpg" medium="image"/><category>Photo Editing</category><category>App Development</category><category>Photo Editor</category><category>JavaScript</category><category>OpenSource</category><category>Background Removal</category><category>Company</category></item></channel></rss>