Learn how to integrate the CreativeEditor SDK (CE.SDK) Engine—without its built-in UI—into a SvelteKit app. This setup is ideal for:
- Building a custom editing interface.
 - Automating creative workflows through code only.
 
What’s CreativeEditor SDK?#
CreativeEditor SDK (CE.SDK) lets you integrate a customizable image and video editor into your web app. It includes filters, text overlays, and other media editing tools, and adapts easily to your use case.
CreativeEditor SDK is a commercial product. To use it, you need a valid license key. If you don’t have one yet, you can get a free trial or purchase a license.
Free TrialPurchase License
Who Is This Guide For?#
This guide is for developers who:
- Want to design a custom UI instead of using CE.SDK’s default editor.
 - Intend to automate workflows.
 - Need to integrate CE.SDK into server components without rendering a visual editor.
 - Have completed a “Getting Started with CE.SDK in SvelteKit” tutorial and are ready to explore more advanced use cases.
 
What You’ll Achieve#
- Integrate CE.SDK’s headless engine into a SvelteKit component.
 - Add code that creates and modifies a CE.SDK scene.
 - Add a custom button that reduces the opacity of an image on each click.
 - (Optional) Render the CE.SDK canvas while still managing the editor with your own UI.
 
Prerequisites#
Before starting, ensure you have:
- A working SvelteKit project.
 - A valid CE.SDK license key.
 
Step 0: Run the Project Locally#
Start your local server at the root of your SvelteKit project. For example:
shell npm run dev  shell yarn dev  shell pnpm run dev  Make sure your SvelteKit app runs without issues before proceeding with this guide.
Step 1: Install CE.SDK Engine#
To use CE.SDK in headless mode in SvelteKit, install the library via the @cesdk/engine package:
npm install @cesdk/engineyarn add @cesdk/enginepnpm add @cesdk/engineStep 2: Create a Custom Component#
Create a custom editor component that runs headless:
- Open the 
src/lib/folder. - Create a file named 
CustomEditor.svelte. - Paste this code into your file:
 
<script>  import { onMount } from 'svelte';  import CreativeEngine from '@cesdk/engine';
  // To store the DOM container where the CreativeEngine canvas will be attached  let canvasContainer;  // To store the CreativeEngine instance  let engine;  // To store the ID of the image block added to the scene  let imageBlockId = null;
  onMount(async () => {    // Your CE.SDK configuration    const config = {      license: '<YOUR_CE_SDK_LICENSE>', // Replace with your CE.SDK license key    };
    // Initialize CreativeEngine in headless mode    engine = await CreativeEngine.init(config);
    // Append CE.SDK canvas to the DOM (optional)    if (canvasContainer && engine.element) {      canvasContainer.appendChild(engine.element);    }
    // Get the current scene or create a new one    let scene = engine.scene.get();    if (!scene) {      scene = engine.scene.create();      const page = engine.block.create('page');      engine.block.appendChild(scene, page);    }
    // Get the first page block    const [page] = engine.block.findByType('page');
    // Append a block to show an image on the page    const imageBlock = engine.block.create('graphic');    imageBlockId = imageBlock;    engine.block.setShape(imageBlock, engine.block.createShape('rect'));
    // Fill the block with an image from a public source    const imageFill = engine.block.createFill('image');    engine.block.setSourceSet(imageFill, 'fill/image/sourceSet', [      {        uri: 'https://img.ly/static/ubq_samples/sample_1_1024x683.jpg',        width: 1024,        height: 683,      },    ]);    engine.block.setFill(imageBlock, imageFill);    engine.block.appendChild(page, imageBlock);
    // Zoom to fit the page in the editor view    engine.scene.zoomToBlock(page);  });
  // Callback to change the opacity of the image  function changeOpacity() {    if (engine && imageBlockId != null) {      // Get the current opacity value of the image      const currentOpacity = engine.block.getOpacity(imageBlockId);      // Reduce the opacity of the image by 20% at each click      engine.block.setOpacity(imageBlockId, currentOpacity * 0.8);    }  }</script>
<div class="editor-container">  <div class="canvas-container" bind:this="{canvasContainer}"></div>  <div class="button-overlay">    <button on:click="{changeOpacity}">Reduce Opacity</button>  </div></div><script>  import { onMount } from 'svelte';  import CreativeEngine from '@cesdk/engine';
  /** @type {HTMLDivElement | null} */    // Your CE.SDK configuration  // To store the DOM container where the CreativeEngine canvas will be attached  let canvasContainer = null;  // To store the CreativeEngine instance    /** @type {any} */  let engine = null;  // To store the ID of the image block added to the scene  /** @type {number | null} */  let imageBlockId = null;
  onMount(async () => {    // Your CE.SDK configuration    const config = {      license: '<YOUR_LICENSE_KEY>', // Replace with your CE.SDK license key    };
    // Initialize CreativeEngine in headless mode    engine = await CreativeEngine.init(config);
    // Append CE.SDK canvas to the DOM (optional)    if (canvasContainer && engine.element) {      canvasContainer.appendChild(engine.element);    }
    // Get the current scene or create a new one    let scene = engine.scene.get();    if (!scene) {      scene = engine.scene.create();      const page = engine.block.create('page');      engine.block.appendChild(scene, page);    }
    // Get the first page block    const [page] = engine.block.findByType('page');
    // Append a block to show an image on the page    const imageBlock = engine.block.create('graphic');    imageBlockId = imageBlock;    engine.block.setShape(imageBlock, engine.block.createShape('rect'));
    // Fill the block with an image from a public source    const imageFill = engine.block.createFill('image');    engine.block.setSourceSet(imageFill, 'fill/image/sourceSet', [      {        uri: 'https://img.ly/static/ubq_samples/sample_1_1024x683.jpg',        width: 1024,        height: 683,      },    ]);    engine.block.setFill(imageBlock, imageFill);    engine.block.appendChild(page, imageBlock);
    // Zoom to fit the page in the editor view    engine.scene.zoomToBlock(page);  });
  // Callback to change the opacity of the image  function changeOpacity() {    if (engine && imageBlockId != null) {      // Get the current opacity value of the image      const currentOpacity = engine.block.getOpacity(imageBlockId);      // Reduce the opacity of the image by 20% at each click      engine.block.setOpacity(imageBlockId, currentOpacity * 0.8);    }  }</script>
<div class="editor-container">  <div class="canvas-container" bind:this="{canvasContainer}"></div>  <div class="button-overlay">    <button on:click="{changeOpacity}">Reduce Opacity</button>  </div></div>Once you’ve initialized CreativeEngine, you can:
- Access the scene.
 - Programmatically create elements.
 - Update the elements’ properties.
 
Understand the Component#
In this example, you do the following:
- Add a sample image to the scene.
 - Create a button that decreases the image’s opacity.
 - With each click of the button, decrease the image’s opacity by 20%.
 
The changeOpacity() function uses the headless CE.SDK block API to:
- Retrieve the image’s current opacity
 - Adjust it dynamically.
 
Style the Component#
Consider styling your custom component with:
<style>.editor-container {  width: 100vw;  height: 100vh;  position: relative;}
.canvas-container {  width: 100%;  height: 100%;}
.button-overlay {  position: absolute;  top: 20px;  left: 20px;}
.button-overlay button {  border-radius: 8px;  border: 1px solid #ccc;  padding: 0.6em 1.2em;  font-size: 1em;  font-weight: 500;  font-family: inherit;  background-color: #ffffff;  color: #1a1a1a;  cursor: pointer;  transition:    border-color 0.25s,    box-shadow 0.25s;  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);}
.button-overlay button:hover {  border-color: #646cff;  box-shadow: 0 4px 10px rgba(100, 108, 255, 0.2);}
.button-overlay button:focus,.button-overlay button:focus-visible {  outline: 2px solid #646cff;  outline-offset: 2px;}</style>Final CustomEditor.svelte file
<script>  import { onMount } from 'svelte';  import CreativeEngine from '@cesdk/engine';
  // To store the DOM container where the CreativeEngine canvas will be attached  let canvasContainer;  // To store the CreativeEngine instance  let engine;  // To store the ID of the image block added to the scene  let imageBlockId = null;
  onMount(async () => {    // Your CE.SDK configuration    const config = {      license: '<YOUR_CE_SDK_LICENSE>', // Replace with your CE.SDK license key    };
    // Initialize CreativeEngine in headless mode    engine = await CreativeEngine.init(config);
    // Append CE.SDK canvas to the DOM (optional)    if (canvasContainer && engine.element) {      canvasContainer.appendChild(engine.element);    }
    // Get the current scene or create a new one    let scene = engine.scene.get();    if (!scene) {      scene = engine.scene.create();      const page = engine.block.create('page');      engine.block.appendChild(scene, page);    }
    // Get the first page block    const [page] = engine.block.findByType('page');
    // Append a block to show an image on the page    const imageBlock = engine.block.create('graphic');    imageBlockId = imageBlock;    engine.block.setShape(imageBlock, engine.block.createShape('rect'));
    // Fill the block with an image from a public source    const imageFill = engine.block.createFill('image');    engine.block.setSourceSet(imageFill, 'fill/image/sourceSet', [      {        uri: 'https://img.ly/static/ubq_samples/sample_1_1024x683.jpg',        width: 1024,        height: 683,      },    ]);    engine.block.setFill(imageBlock, imageFill);    engine.block.appendChild(page, imageBlock);
    // Zoom to fit the page in the editor view    engine.scene.zoomToBlock(page);  });
  // Callback to change the opacity of the image  function changeOpacity() {    if (engine && imageBlockId != null) {      // Get the current opacity value of the image      const currentOpacity = engine.block.getOpacity(imageBlockId);      // Reduce the opacity of the image by 20% at each click      engine.block.setOpacity(imageBlockId, currentOpacity * 0.8);    }  }</script>
<div class="editor-container">  <div class="canvas-container" bind:this="{canvasContainer}"></div>  <div class="button-overlay">    <button on:click="{changeOpacity}">Reduce Opacity</button>  </div></div>
<style>.editor-container {  width: 100vw;  height: 100vh;  position: relative;}
.canvas-container {  width: 100%;  height: 100%;}
.button-overlay {  position: absolute;  top: 20px;  left: 20px;}
.button-overlay button {  border-radius: 8px;  border: 1px solid #ccc;  padding: 0.6em 1.2em;  font-size: 1em;  font-weight: 500;  font-family: inherit;  background-color: #ffffff;  color: #1a1a1a;  cursor: pointer;  transition:    border-color 0.25s,    box-shadow 0.25s;  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);}
.button-overlay button:hover {  border-color: #646cff;  box-shadow: 0 4px 10px rgba(100, 108, 255, 0.2);}
.button-overlay button:focus,.button-overlay button:focus-visible {  outline: 2px solid #646cff;  outline-offset: 2px;}</style><script>  import { onMount } from 'svelte';  import CreativeEngine from '@cesdk/engine';
  /** @type {HTMLDivElement | null} */    // Your CE.SDK configuration  // To store the DOM container where the CreativeEngine canvas will be attached  let canvasContainer = null;  // To store the CreativeEngine instance    /** @type {any} */  let engine = null;  // To store the ID of the image block added to the scene  /** @type {number | null} */  let imageBlockId = null;
  onMount(async () => {    // Your CE.SDK configuration    const config = {      license: '<YOUR_LICENSE_KEY>', // Replace with your CE.SDK license key    };
    // Initialize CreativeEngine in headless mode    engine = await CreativeEngine.init(config);
    // Append CE.SDK canvas to the DOM (optional)    if (canvasContainer && engine.element) {      canvasContainer.appendChild(engine.element);    }
    // Get the current scene or create a new one    let scene = engine.scene.get();    if (!scene) {      scene = engine.scene.create();      const page = engine.block.create('page');      engine.block.appendChild(scene, page);    }
    // Get the first page block    const [page] = engine.block.findByType('page');
    // Append a block to show an image on the page    const imageBlock = engine.block.create('graphic');    imageBlockId = imageBlock;    engine.block.setShape(imageBlock, engine.block.createShape('rect'));
    // Fill the block with an image from a public source    const imageFill = engine.block.createFill('image');    engine.block.setSourceSet(imageFill, 'fill/image/sourceSet', [      {        uri: 'https://img.ly/static/ubq_samples/sample_1_1024x683.jpg',        width: 1024,        height: 683,      },    ]);    engine.block.setFill(imageBlock, imageFill);    engine.block.appendChild(page, imageBlock);
    // Zoom to fit the page in the editor view    engine.scene.zoomToBlock(page);  });
  // Callback to change the opacity of the image  function changeOpacity() {    if (engine && imageBlockId != null) {      // Get the current opacity value of the image      const currentOpacity = engine.block.getOpacity(imageBlockId);      // Reduce the opacity of the image by 20% at each click      engine.block.setOpacity(imageBlockId, currentOpacity * 0.8);    }  }</script>
<div class="editor-container">  <div class="canvas-container" bind:this="{canvasContainer}"></div>  <div class="button-overlay">    <button on:click="{changeOpacity}">Reduce Opacity</button>  </div></div>
<style>.editor-container {  width: 100vw;  height: 100vh;  position: relative;}
.canvas-container {  width: 100%;  height: 100%;}
.button-overlay {  position: absolute;  top: 20px;  left: 20px;}
.button-overlay button {  border-radius: 8px;  border: 1px solid #ccc;  padding: 0.6em 1.2em;  font-size: 1em;  font-weight: 500;  font-family: inherit;  background-color: #ffffff;  color: #1a1a1a;  cursor: pointer;  transition:    border-color 0.25s,    box-shadow 0.25s;  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);}
.button-overlay button:hover {  border-color: #646cff;  box-shadow: 0 4px 10px rgba(100, 108, 255, 0.2);}
.button-overlay button:focus,.button-overlay button:focus-visible {  outline: 2px solid #646cff;  outline-offset: 2px;}</style>Optional: Export Component Using the Module System#
If you organize your SvelteKit project’s components in a single src/lib/index.js file, add the following line to index.js:
export { default as CustomEditor } from './CustomEditor.svelte';Step 3: Use the Custom Editor Component#
CreativeEngine only operates in the browser. To handle client-side rendering, you need to:
- Import the component in a route file.
 - Render the component on a page when the app is running in the browser.
 
Import the CustomEditor Component#
Dynamically import and render the CustomEditor component as follows:
- Open the relevant SSR route file, which should contain the component (for example, 
src/routes/+page.svelte). - Navigate to the 
<script>section. - Paste this code to dynamically import the 
CustomEditorcomponent: 
<script>  import { browser } from "$app/environment"; // True only if the app is running in the browser  // Use the browser flag to conditionally render client-side components  let isClient = browser;
  let CustomEditor;  if (isClient) {    // Dynamically import the CustomEditor component only in the browser    import("$components/CustomEditor.svelte").then(module => {      CustomEditor = module.default;    });  }
</script><script lang="ts">  import { browser } from "$app/environment"; // True only if the app is running in the browser  // Use the browser flag to conditionally render client-side components  let isClient = browser;
  import type { ComponentType } from "svelte";  let CustomEditor: ComponentType | null = null;  if (isClient) {    // Dynamically import the CustomEditor component only in the browser    import("$components/CustomEditor.svelte").then(module => {      CustomEditor = module.default;    });  }     </script>Optional: Import Components Using the Module System#
If you exported CustomEditor from src/lib/index.js, you can simplify the dynamic import:
import("$lib").then(module => {CustomEditor = module.CustomEditor;});Render the CreativeEditorSDK Component#
Render the component only on the client::
- Navigate to the template section of your SvelteKit route or component
 - Wrap the component like this:
 
    // </script>    {#if isClient && CustomEditor}      <CustomEditor />    {/if}Final +page.svelte file
<script>  import { browser } from "$app/environment"; // True only if the app is running in the browser  // Use the browser flag to conditionally render client-side components  let isClient = browser;
  let CustomEditor;  if (isClient) {    // Dynamically import the CustomEditor component only in the browser    import("$components/CustomEditor.svelte").then(module => {      CustomEditor = module.default;    });  }
</script>
{#if isClient && CustomEditor}  <CustomEditor />{/if}<script lang="ts">  import { browser } from "$app/environment"; // True only if the app is running in the browser  // Use the browser flag to conditionally render client-side components  let isClient = browser;
  import type { ComponentType } from "svelte";  let CustomEditor: ComponentType | null = null;  if (isClient) {    // Dynamically import the CustomEditor component only in the browser    import("$components/CustomEditor.svelte").then(module => {      CustomEditor = module.default;    });  }
</script>
{#if isClient && CustomEditor}
<CustomEditor />{/if}Verify the integration works:
- Navigate to the page containing 
<CustomEditor>. - Check the existence of a sample image on the canvas, along with a “Reduce Opacity” button.
 - Click the button to reduce the image’s opacity by 20% each time.
 
Use Cases#
Congratulations! You’ve laid the groundwork for:
- Building fully customized creative tools with SvelteKit.
 - Automating the generation of graphics and visual content.
 - Managing the CE.SDK engine through code in browser-based workflows.
 - Developing server-side image or video manipulation features using 
@cesdk/node. 
Troubleshooting & Common Errors#
❌ Error: Error when evaluating SSR module /src/routes/+page.svelte: document is not defined
- 
Verify that you integrate the
CustomEditorcomponent using: - 
Dynamic import in
/src/routes/+page.svelte. - 
Client side rendering only.
 
❌ Error: CE.SDK canvas doesn’t render
- Make sure you append 
engine.elementto an HTML element that already exists in the page. - Double-check that the container element:
 
- Exists in the DOM when you call 
appendChild. - Renders or mounts before the code initializes the engine.
 
❌ Error: Internal server error: Failed to resolve import "@cesdk/engine" from "src/lib/CustomEditor.svelte". Does the file exist?
- Confirm that you’ve installed CreativeEngine using the install command.
 
❌ Error: Missing license key in config
- Ensure your 
configobject: 
- Includes a 
licenseproperty. - You’ve set the 
licenseproperty to your CE.SDK license key. 
❌ Error: Editor engine could not be loaded: The License Key (API Key) you are using to access CE.SDK is invalid
- Verify that your license key is correct, hasn’t expired, and is properly added to the configuration.
 
❌ Issue: The component doesn’t behave as expected
- Double-check your component paths and import statements.
 - Open the browser console and inspect any runtime errors that might help identify the issue.
 
Next Steps#
This guide has set the stage for:
- Creating a full custom UI with SvelteKit.
 - Automating the export of scenes.
 - Batch processing graphics or template content.