<?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>Angular – IMG.LY Blog</title><description>Posts tagged Angular on the IMG.LY blog.</description><link>https://img.ly/blog/tag/angular/</link><language>en-us</language><image><url>https://img.ly/apple-touch-icon.png</url><title>Angular – IMG.LY Blog</title><link>https://img.ly/blog/tag/angular/</link></image><atom:link href="https://img.ly/blog/tag/angular/rss.xml" rel="self" type="application/rss+xml"/><generator>Astro</generator><lastBuildDate>Wed, 14 Oct 2026 14:42:51 GMT</lastBuildDate><ttl>60</ttl><item><title>A Modern Angular Video Editor: Setup Guide</title><link>https://img.ly/blog/a-modern-angular-video-editor/</link><guid isPermaLink="true">https://img.ly/blog/a-modern-angular-video-editor/</guid><description>Learn how to integrate IMG.LY&apos;s video editor for Angular into your web app, from the component scaffold to timeline edits and MP4 export.</description><pubDate>Wed, 08 Jan 2025 08:19:25 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Learn how to integrate&lt;/em&gt; &lt;a href=&quot;https://img.ly/docs/cesdk/angular/starterkits/video-editor-e1nlor/&quot;&gt;&lt;em&gt;IMG.LY’s video editor&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for Angular into your web application.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;People who trim and caption clips daily in TikTok or CapCut expect the same inside your product. When they cannot, they export, edit elsewhere, and upload again. Each round trip is a chance to abandon the task, and every asset that leaves your system stops being one you can template or keep on brand.&lt;/p&gt;
&lt;p&gt;This guide covers adding a video editor to an Angular app with CreativeEditor SDK (CE.SDK): the component wiring, the timeline and export APIs underneath, and the customization points you will reach for once it runs.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Updated September 2026.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;check-browser-support-before-you-scope-the-work&quot;&gt;Check browser support before you scope the work&lt;/h2&gt;
&lt;p&gt;CE.SDK’s video features encode and decode in the browser through the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebCodecs_API&quot;&gt;WebCodecs API&lt;/a&gt;. That is what makes client-side MP4 export possible without a render backend, and it is also the constraint. Chrome and Edge 114 or newer support both video editing and export, and so does Safari 26 or newer. Firefox 130 or newer can edit video but cannot export it, because it does not ship the H.264 and AAC encoders the export needs. Chrome on Linux usually lacks those encoders as well, so exports can fail there. Chrome on Android and iOS and Safari on iOS do not support video editing yet, and other Chromium-based browsers such as Opera, Arc, and Brave may work but are not officially supported.&lt;/p&gt;
&lt;p&gt;Design and photo editing work in more browsers. If a meaningful share of your users are on Firefox, mobile, or older Safari versions, plan a fallback now rather than in QA. &lt;code&gt;cesdk.utils.supportsVideoDecode()&lt;/code&gt; and &lt;code&gt;await cesdk.utils.supportsVideoEncode()&lt;/code&gt; check support in code, and the &lt;a href=&quot;https://img.ly/docs/cesdk/angular/browser-support-28c1b0/&quot;&gt;browser support page&lt;/a&gt; has the details.&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;CE.SDK ships an Angular component, just like it does for React and Vue. Import &lt;code&gt;CreativeEditor&lt;/code&gt; from the &lt;code&gt;/angular&lt;/code&gt; entry point, give it a &lt;code&gt;config&lt;/code&gt; object and an &lt;code&gt;init&lt;/code&gt; function, and it creates the editor when the view is ready and disposes of it when your component is destroyed.&lt;/p&gt;
&lt;h3 id=&quot;requirements&quot;&gt;Requirements&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Node.js 22.22.3+, 24.15+, or 26+, which the Angular CLI requires. &lt;a href=&quot;https://nodejs.org/download&quot;&gt;Download Node.js&lt;/a&gt; if needed.&lt;/li&gt;
&lt;li&gt;An Angular project. If you do not have one, install the CLI with &lt;code&gt;npm install -g @angular/cli&lt;/code&gt;, run &lt;code&gt;ng new my-angular-video-editor&lt;/code&gt;, and answer its prompts.&lt;/li&gt;
&lt;li&gt;A CE.SDK license key, optional to start and needed for production. &lt;a href=&quot;https://img.ly/docs/cesdk/&quot;&gt;Start a free trial&lt;/a&gt; to get one.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;step-1-install-cesdk&quot;&gt;Step 1: Install CE.SDK&lt;/h3&gt;
&lt;p&gt;Install the SDK together with the background removal plugin that the editor configuration below uses:&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@1.82.0&lt;/span&gt;&lt;span&gt; @imgly/plugin-background-removal-web@1.82.0&lt;/span&gt;&lt;span&gt; onnxruntime-web@1.21.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-2-add-the-video-editor-configuration&quot;&gt;Step 2: Add the video editor configuration&lt;/h3&gt;
&lt;p&gt;The editor’s dock, inspector, timeline controls, and asset libraries come from an editor configuration. The &lt;a href=&quot;https://img.ly/docs/cesdk/angular/starterkits/video-editor-e1nlor/&quot;&gt;Angular video editor starter kit&lt;/a&gt; ships it as source files, so copy them into 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;npx&lt;/span&gt;&lt;span&gt; degit&lt;/span&gt;&lt;span&gt; imgly/starterkit-video-editor-ts-web/src/imgly#release-1.82.0&lt;/span&gt;&lt;span&gt; src/app/imgly&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;release-1.82.0&lt;/code&gt; tag matches the SDK version from Step 1. You change the editor by editing these files.&lt;/p&gt;
&lt;h3 id=&quot;step-3-generate-the-component&quot;&gt;Step 3: Generate the component&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ng&lt;/span&gt;&lt;span&gt; generate&lt;/span&gt;&lt;span&gt; component&lt;/span&gt;&lt;span&gt; video-editor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates &lt;code&gt;video-editor.ts&lt;/code&gt;, &lt;code&gt;video-editor.html&lt;/code&gt;, and &lt;code&gt;video-editor.css&lt;/code&gt;, plus a test file, in &lt;code&gt;src/app/video-editor/&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;step-4-wire-up-the-editor&quot;&gt;Step 4: Wire up the editor&lt;/h3&gt;
&lt;p&gt;Open &lt;code&gt;src/app/video-editor/video-editor.ts&lt;/code&gt; and add the editor configuration and the &lt;code&gt;init&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// src/app/video-editor/video-editor.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { Component } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@angular/core&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; type&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; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  CreativeEditor,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  type&lt;/span&gt;&lt;span&gt; CreativeEditorError,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@cesdk/cesdk-js/angular&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; { initVideoEditor } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;../imgly&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Component&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  selector: &lt;/span&gt;&lt;span&gt;&apos;app-video-editor&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  imports: [CreativeEditor],&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.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.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; VideoEditor&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  config&lt;/span&gt;&lt;span&gt; =&lt;/span&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;YOUR_USER_ID&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// optional, for MAU tracking&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  };&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; async&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;cesdk&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; CreativeEditorSDK&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;    // Video editor UI, asset libraries and plugins from the starter kit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    await&lt;/span&gt;&lt;span&gt; initVideoEditor&lt;/span&gt;&lt;span&gt;(cesdk);&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 an empty video scene&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    await&lt;/span&gt;&lt;span&gt; cesdk.actions.&lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;scene.create&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;  onError&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; CreativeEditorError&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;    console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;[CE.SDK]&apos;&lt;/span&gt;&lt;span&gt;, error.message, error.cause);&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;You do not need a CE.SDK license key to try it: without one the editor runs in evaluation mode and exports carry a watermark. &lt;a href=&quot;https://img.ly/docs/cesdk/&quot;&gt;Start a free trial&lt;/a&gt; to get one and set it as &lt;code&gt;license&lt;/code&gt; in the config.&lt;/p&gt;
&lt;p&gt;Then use the component in &lt;code&gt;video-editor.html&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;creative-editor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  [config]&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;config&quot;&lt;/span&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;&quot;init&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  [onError]&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;onError&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  width&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;100vw&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  height&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;100vh&quot;&lt;/span&gt;&lt;/span&gt;
&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;A few details are worth knowing here.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;initVideoEditor&lt;/code&gt; applies the configuration and adds the asset libraries, including demo clips and music, upload sources, and background removal. In production, swap the demo sources in &lt;code&gt;src/app/imgly/index.ts&lt;/code&gt; for your own.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cesdk.actions.run(&apos;scene.create&apos;)&lt;/code&gt; opens an empty scene. Since CE.SDK 1.72 deprecated the design and video scene modes, every new scene supports video. Older examples that call &lt;code&gt;createVideoScene()&lt;/code&gt; or &lt;code&gt;addDemoAssetSources()&lt;/code&gt; still work, but both are deprecated. One caveat: the iOS and Android SDKs do not yet support scenes without a mode, so if you share scenes with mobile apps, read the &lt;a href=&quot;https://img.ly/docs/cesdk/angular/to-v1-72-b37fa1/&quot;&gt;v1.72 migration guide&lt;/a&gt; first.&lt;/p&gt;
&lt;p&gt;The configuration also runs &lt;code&gt;editor.checkBrowserSupport&lt;/code&gt;, which shows a blocking message in browsers that cannot decode video and a dismissible warning in browsers that cannot export it. Since CE.SDK 1.72, the editor no longer runs this check on its own, so keep that call if you replace the configuration.&lt;/p&gt;
&lt;p&gt;The editor loads its engine assets from the IMG.LY CDN, which is meant for development. For production, &lt;a href=&quot;https://img.ly/docs/cesdk/angular/serve-assets-b0827c/&quot;&gt;serve the assets from your own servers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If anything inside &lt;code&gt;init&lt;/code&gt; throws, the component catches the error and passes it to &lt;code&gt;onError&lt;/code&gt;. Without that binding, the error never reaches the console, which is why the template binds it.&lt;/p&gt;
&lt;h3 id=&quot;step-5-use-the-component&quot;&gt;Step 5: Use the component&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// src/app/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { Component } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@angular/core&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { VideoEditor } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./video-editor/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;
&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: [VideoEditor],&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.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.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; App&lt;/span&gt;&lt;span&gt; {}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And replace the contents of &lt;code&gt;app.html&lt;/code&gt; with:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;app-video-editor&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The copied configuration needs one change on the 1.82.0 release. Both &lt;code&gt;ng serve&lt;/code&gt; and &lt;code&gt;ng build&lt;/code&gt; stop with a &lt;code&gt;TS2345&lt;/code&gt; error on &lt;code&gt;features/videoCaptionsEnabled&lt;/code&gt; in &lt;code&gt;src/app/imgly/config/settings.ts&lt;/code&gt;, because the engine uses that setting to enable captions but the 1.82.0 type definitions do not list it yet, and Angular type-checks the copied files. Cast the key and value on that line to keep captions enabled:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.editor.&lt;/span&gt;&lt;span&gt;setSetting&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;features/videoCaptionsEnabled&apos;&lt;/span&gt;&lt;span&gt; as&lt;/span&gt;&lt;span&gt; never&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  true&lt;/span&gt;&lt;span&gt; as&lt;/span&gt;&lt;span&gt; never&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;Also add &lt;code&gt;body { margin: 0; }&lt;/code&gt; to &lt;code&gt;src/styles.css&lt;/code&gt;, so the full-width editor does not overflow the page.&lt;/p&gt;
&lt;p&gt;Run &lt;code&gt;ng serve&lt;/code&gt;. You should get a full editor with a timeline: trimming, splitting, text overlays, audio tracks, filters, and transitions. Compare against the &lt;a href=&quot;https://img.ly/demos/video-ui/web/&quot;&gt;interactive demo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before you run &lt;code&gt;ng build&lt;/code&gt;, raise the bundle budget. CE.SDK is larger than the default budget of a new Angular app, so the production build fails with a “bundle initial exceeded maximum budget” error. In &lt;code&gt;angular.json&lt;/code&gt;, change the &lt;code&gt;initial&lt;/code&gt; budget under &lt;code&gt;configurations.production&lt;/code&gt; the way the CE.SDK starter kit does:&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;budgets&quot;&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;type&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;initial&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;maximumWarning&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;3MB&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;maximumError&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;5MB&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&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;type&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;anyComponentStyle&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;maximumWarning&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;4kB&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;maximumError&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;8kB&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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;two-more-things-that-bite&quot;&gt;Two more things that bite&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Relative asset URLs resolve against the CDN.&lt;/strong&gt; Because &lt;code&gt;config.baseURL&lt;/code&gt; defaults to IMG.LY’s CDN, a relative URI like &lt;code&gt;/videos/intro.mp4&lt;/code&gt; resolves there rather than against your own origin. Make local asset paths absolute before handing them to the engine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Server-side rendering needs a boundary.&lt;/strong&gt; The editor is browser-only. If your app uses server-side rendering, wrap the component in a &lt;code&gt;@defer&lt;/code&gt; block, which renders only its placeholder on the server:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;@defer {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;app-video-editor&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;} @placeholder {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;Loading editor...&amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&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;h2 id=&quot;let-an-agent-do-the-integration&quot;&gt;Let an agent do the integration&lt;/h2&gt;
&lt;p&gt;If you work in an AI-assisted editor, &lt;a href=&quot;https://img.ly/docs/cesdk/angular/get-started/agent-skills-f7g8h9/&quot;&gt;Agent Skills for CE.SDK&lt;/a&gt; load CE.SDK’s current documentation and conventions into Claude Code, Codex, and similar tools, so the code you get back matches the current API instead of a remembered one. There is also an &lt;a href=&quot;https://img.ly/docs/cesdk/angular/get-started/mcp-server-fde71c/&quot;&gt;MCP server&lt;/a&gt; for live lookup during a session. Background in &lt;a href=&quot;https://img.ly/blog/img-ly-agent-skills-web/&quot;&gt;Introducing IMG.LY Agent Skills&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;building-compositions-in-code&quot;&gt;Building compositions in code&lt;/h2&gt;
&lt;p&gt;The default UI covers user-facing editing. For templates, automation, or a custom interface, go through &lt;code&gt;cesdk.engine&lt;/code&gt;, for example inside &lt;code&gt;init&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;scene-and-page&quot;&gt;Scene and page&lt;/h3&gt;
&lt;p&gt;A page owns a timeline. Its duration comes from the clips you put on it, and that is the duration of the export.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; engine&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; cesdk.engine;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; scene&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.scene.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; page&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;page&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(scene, page);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setWidth&lt;/span&gt;&lt;span&gt;(page, &lt;/span&gt;&lt;span&gt;1280&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setHeight&lt;/span&gt;&lt;span&gt;(page, &lt;/span&gt;&lt;span&gt;720&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;clips-and-tracks&quot;&gt;Clips and tracks&lt;/h3&gt;
&lt;p&gt;Video is not its own block type. A &lt;code&gt;graphic&lt;/code&gt; block with a video fill gets you the same positioning and animation APIs as any other element. The background track keeps children playing back to back, recalculates offsets when durations change, and sets the page duration. The timeline shows every track on the page, including ones you create yourself.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; clip1&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;graphic&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setShape&lt;/span&gt;&lt;span&gt;(clip1, engine.block.&lt;/span&gt;&lt;span&gt;createShape&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;rect&apos;&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; fill1&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;createFill&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;video&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  fill1,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;fill/video/fileURI&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;https://cdn.img.ly/assets/demo/v4/ly.img.video/videos/pexels-drone-footage-of-a-surfer-barrelling-a-wave-12715991.mp4&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setFill&lt;/span&gt;&lt;span&gt;(clip1, fill1);&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; clip2&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;graphic&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setShape&lt;/span&gt;&lt;span&gt;(clip2, engine.block.&lt;/span&gt;&lt;span&gt;createShape&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;rect&apos;&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; fill2&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;createFill&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;video&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  fill2,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;fill/video/fileURI&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;https://cdn.img.ly/assets/demo/v4/ly.img.video/videos/pexels-taryn-elliott-7108793.mp4&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setFill&lt;/span&gt;&lt;span&gt;(clip2, fill2);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;moveToBackgroundTrack&lt;/span&gt;&lt;span&gt;(clip1);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; track&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;getBackgroundTrack&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (track &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;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;&apos;No background track&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setDuration&lt;/span&gt;&lt;span&gt;(clip1, &lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// set it before clip2 joins&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;moveToBackgroundTrack&lt;/span&gt;&lt;span&gt;(clip2); &lt;/span&gt;&lt;span&gt;// the track shifts it to 10s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;fillParent&lt;/span&gt;&lt;span&gt;(track);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Size the children rather than the track. A track takes its dimensions from what it holds, and &lt;code&gt;moveToBackgroundTrack&lt;/code&gt; creates the background track the first time you call it. &lt;code&gt;getBackgroundTrack&lt;/code&gt; is typed as nullable, so TypeScript needs the check above before the id is used.&lt;/p&gt;
&lt;h3 id=&quot;trim-and-audio&quot;&gt;Trim and audio&lt;/h3&gt;
&lt;p&gt;Blocks default to 5 seconds. Longer clips get cut off, shorter ones stop at their end unless you call &lt;code&gt;engine.block.setLooping(fill, true)&lt;/code&gt;. Trim APIs need duration metadata, so load the resource first.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;forceLoadAVResource&lt;/span&gt;&lt;span&gt;(fill1);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setTrimOffset&lt;/span&gt;&lt;span&gt;(fill1, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setTrimLength&lt;/span&gt;&lt;span&gt;(fill1, &lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setMuted&lt;/span&gt;&lt;span&gt;(fill1, &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; audio&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;audio&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(page, audio);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  audio,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;audio/fileURI&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;https://cdn.img.ly/assets/demo/v4/ly.img.audio/audios/far_from_home.m4a&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setVolume&lt;/span&gt;&lt;span&gt;(audio, &lt;/span&gt;&lt;span&gt;0.7&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setTimeOffset&lt;/span&gt;&lt;span&gt;(audio, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Skipping &lt;code&gt;forceLoadAVResource&lt;/code&gt; is a common bug: the trim calls throw &lt;code&gt;The video has not been loaded yet.&lt;/code&gt;, the &lt;code&gt;onError&lt;/code&gt; output receives it, and every line after it is skipped, so the mute and the audio block never run either.&lt;/p&gt;
&lt;h3 id=&quot;export-to-mp4&quot;&gt;Export to MP4&lt;/h3&gt;
&lt;p&gt;Encoding runs in a background worker, so the editor stays responsive. The scene freezes at the start of the export, so later edits will not appear in the output.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; exportPage&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.scene.&lt;/span&gt;&lt;span&gt;getCurrentPage&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;exportPage) &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;&apos;No page to export&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; 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;(exportPage, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  mimeType: &lt;/span&gt;&lt;span&gt;&apos;video/mp4&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  videoBitrate: &lt;/span&gt;&lt;span&gt;&apos;Auto&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// bounded bitrate, recommended in the browser&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  onProgress&lt;/span&gt;&lt;span&gt;: (&lt;/span&gt;&lt;span&gt;rendered&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;encoded&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;total&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    this&lt;/span&gt;&lt;span&gt;.progress.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(Math.&lt;/span&gt;&lt;span&gt;round&lt;/span&gt;&lt;span&gt;((encoded &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; total) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; anchor&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;a&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;anchor.href &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; URL&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;createObjectURL&lt;/span&gt;&lt;span&gt;(blob);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;anchor.download &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;export.mp4&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;anchor.&lt;/span&gt;&lt;span&gt;click&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Declare &lt;code&gt;progress = signal(0)&lt;/code&gt; on your component, adding &lt;code&gt;signal&lt;/code&gt; to the &lt;code&gt;@angular/core&lt;/code&gt; import, and read &lt;code&gt;progress()&lt;/code&gt; in the template, and you have a progress bar. New Angular components use OnPush change detection by default, so a signal is what keeps the view in sync. Encoding a long composition takes time, and an unexplained wait reads as a hang.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;engine.block.exportAudio(page, { mimeType: &apos;audio/wav&apos; })&lt;/code&gt;, still marked experimental in the SDK types, extracts just the audio, which is useful for transcription and captioning. On that note, &lt;a href=&quot;https://img.ly/docs/cesdk/angular/create-video/update-caption-presets-e9c385/&quot;&gt;caption presets&lt;/a&gt; and &lt;a href=&quot;https://img.ly/docs/cesdk/angular/create-video/apply-transitions-146026/&quot;&gt;transitions&lt;/a&gt; are both worth exploring once the basics work.&lt;/p&gt;
&lt;p&gt;Full reference: the &lt;a href=&quot;https://img.ly/docs/cesdk/angular/create-video/overview-b06512/&quot;&gt;create and edit videos guide&lt;/a&gt; and the &lt;a href=&quot;https://img.ly/docs/cesdk/angular/create-video/timeline-editor-912252/&quot;&gt;timeline editor docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;customizing-the-editor&quot;&gt;Customizing the editor&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Component order.&lt;/strong&gt; Add, remove, and reorder UI elements with &lt;code&gt;setComponentOrder({ in: location }, order)&lt;/code&gt; across locations such as &lt;code&gt;&apos;ly.img.dock&apos;&lt;/code&gt;, &lt;code&gt;&apos;ly.img.canvas.menu&apos;&lt;/code&gt;, and &lt;code&gt;&apos;ly.img.inspector.bar&apos;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Roles.&lt;/strong&gt; &lt;a href=&quot;https://img.ly/docs/cesdk/angular/configuration-2c1c3d/&quot;&gt;CE.SDK supports roles&lt;/a&gt;, which bundle global settings and scopes. Switching role applies that role’s defaults, and you can adjust individual scopes for specific workflows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Theming.&lt;/strong&gt; &lt;code&gt;cesdk.ui.setTheme()&lt;/code&gt; for light, dark, or system, or build a &lt;a href=&quot;https://img.ly/docs/cesdk/angular/user-interface/appearance/theming-4b0938/&quot;&gt;custom theme&lt;/a&gt; with CSS custom properties. See the &lt;a href=&quot;https://img.ly/demos/theming/web/&quot;&gt;theming demo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Export options.&lt;/strong&gt; Control which formats users can export, plus quality and dimensions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Asset libraries.&lt;/strong&gt; Serve media from your own backend or connect a third-party source.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Localization.&lt;/strong&gt; Override and extend every string with &lt;a href=&quot;https://img.ly/docs/cesdk/angular/user-interface/localization-508e20/&quot;&gt;full i18n support&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Package reusable customizations as a &lt;a href=&quot;https://img.ly/docs/cesdk/angular/user-interface/ui-extensions-d194d1/&quot;&gt;plugin&lt;/a&gt;. Background removal and vectorization ship that way.&lt;/p&gt;
&lt;h2 id=&quot;where-an-angular-video-editor-pays-off&quot;&gt;Where an Angular video editor pays off&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Marketing outreach.&lt;/strong&gt; Personalized video at volume beats a cold email, and &lt;a href=&quot;https://img.ly/docs/cesdk/angular/create-templates/add-dynamic-content/text-variables-7ecb50/&quot;&gt;text variables&lt;/a&gt; plus &lt;a href=&quot;https://img.ly/demos/language/web/&quot;&gt;localization&lt;/a&gt; make per-recipient variants a data problem rather than an editing one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;E-learning.&lt;/strong&gt; Instructors record, trim, and caption in the browser and build a template library instead of one-off files. &lt;a href=&quot;https://img.ly/docs/cesdk/angular/user-interface/ui-extensions-d194d1/&quot;&gt;Plugins&lt;/a&gt; can add quizzes and polls.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Social publishing.&lt;/strong&gt; Templates, an audio library, and &lt;a href=&quot;https://img.ly/docs/cesdk/angular/animation/overview-6a2ef2/&quot;&gt;configurable animations&lt;/a&gt;, then export per platform aspect ratio.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;E-commerce.&lt;/strong&gt; Short product videos give shoppers a clearer look at what they are buying. Templates plus product data generate variations at catalog scale without a designer per SKU.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Creative automation.&lt;/strong&gt; Define templates once, then feed them from your data to produce campaign variants. Combined with A/B testing, teams ship several cuts and keep the one that performs.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;Start from the &lt;a href=&quot;https://img.ly/docs/cesdk/angular/starterkits/video-editor-e1nlor/&quot;&gt;Angular video editor starter kit&lt;/a&gt;, which is a working project rather than a snippet, or try the &lt;a href=&quot;https://img.ly/demos/video-ui/web/&quot;&gt;demo&lt;/a&gt; first.&lt;/p&gt;
&lt;p&gt;Building the same thing elsewhere? We have equivalent guides for &lt;a href=&quot;https://img.ly/blog/a-modern-react-video-editor/&quot;&gt;React&lt;/a&gt; and &lt;a href=&quot;https://img.ly/blog/a-modern-vue-js-video-editor/&quot;&gt;Vue.js&lt;/a&gt;, plus a broader &lt;a href=&quot;https://img.ly/blog/javascript-video-editing-guide/&quot;&gt;JavaScript video editing guide&lt;/a&gt; on the underlying browser technology. Still comparing options? See our breakdown of the &lt;a href=&quot;https://img.ly/blog/top-7-video-editing-sdks-in-2025/&quot;&gt;leading video editing SDKs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Questions about your use case? &lt;a href=&quot;https://img.ly/forms/contact-sales/&quot;&gt;Talk to us&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;faq&quot;&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Does CE.SDK have an Angular component?&lt;/strong&gt;
Yes. Import CreativeEditor from @cesdk/cesdk-js/angular. It is a standalone component that creates the editor when the view is ready and disposes of it when your component is destroyed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why does ng build fail after adding CE.SDK?&lt;/strong&gt;
A new Angular app fails the build when the initial bundle passes 1 MB, and CE.SDK is larger than that. Raise the initial budget in angular.json, for example to a 3 MB warning and a 5 MB error, as the CE.SDK starter kit does.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Can I use CE.SDK with Angular server-side rendering?&lt;/strong&gt;
Yes, as long as the editor only renders in the browser. Wrap the component in a @defer block, which renders only its placeholder on the server.&lt;/p&gt;
</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2025/01/video-editor-angular.jpg" medium="image"/><category>Angular</category><category>How-To</category><category>Video Editor</category><category>Video Editing</category></item></channel></rss>