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_CESDK_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_CESDK_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.