# SvelteKit Project Without UI

Learn how to integrate the [CreativeEditor SDK (CE.SDK) Engine](sveltekit/engine-interface-6fb7cf/) —_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?[#](#whats-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 Trial](https://img.ly/forms/free-trial)[

Purchase License

](https://img.ly/pricing)

## Who Is This Guide For?[#](#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[#](#what-youll-achieve)

1.  Integrate CE.SDK’s **headless engine** into a SvelteKit component.
2.  Add code that creates and modifies a [CE.SDK scene](sveltekit/concepts/scenes-e8596d/) .
3.  Add a custom button that reduces the opacity of an image on each click.
4.  _(Optional)_ Render the CE.SDK canvas while still managing the editor with your own UI.

## Prerequisites[#](#prerequisites)

Before starting, ensure you have:

*   A working SvelteKit project.
*   A valid **CE.SDK license key**.

## Step 0: Run the Project Locally[#](#step-0-run-the-project-locally)

Start your local server at the root of your SvelteKit project. For example:

[

npm

](#tab-panel-99)[

yarn

](#tab-panel-100)[

pnpm

](#tab-panel-101)

`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[#](#step-1-install-cesdk-engine)

To use CE.SDK in headless mode in SvelteKit, install the library via the [`@cesdk/engine`](https://www.npmjs.com/package/@cesdk/engine) package:

[

npm

](#tab-panel-102)[

yarn

](#tab-panel-103)[

pnpm

](#tab-panel-104)

Terminal window

```
npm install @cesdk/engine
```

Terminal window

```
yarn add @cesdk/engine
```

Terminal window

```
pnpm add @cesdk/engine
```

## Step 2: Create a Custom Component[#](#step-2-create-a-custom-component)

Create a custom editor component that runs headless:

1.  Open the `src/lib/` folder.
2.  Create a file named `CustomEditor.svelte`.
3.  Paste this code into your file:

[

JavaScript

](#tab-panel-111)[

TypeScript

](#tab-panel-112)

Replace `YOUR_LICENSE_KEY` with your **license key**.

CustomEditor.svelte

```
<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>
```

Replace `YOUR_LICENSE_KEY` with your **license key**.

CustomEditor.svelte

```
<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[#](#understand-the-component)

In this example, you do the following:

1.  Add a sample image to the scene.
2.  Create a button that decreases the image’s opacity.
3.  With each click of the button, decrease the image’s opacity by 20%.

The `changeOpacity()` function uses the **headless [CE.SDK `block` API](sveltekit/concepts/blocks-90241e/)** to:

*   Retrieve the image’s current opacity
*   Adjust it dynamically.

Rendering the CE.SDK canvas on the front end is **optional**. You can use the engine entirely for automated processing in the browser—no UI required. For example, you could:

1.  Reduce the opacity of an image in memory.
2.  Export it **without ever rendering it on screen**.

### Style the Component[#](#style-the-component)

Consider styling your custom component with:

CustomEditor.svelte

```
<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  

[

JavaScript

](#tab-panel-105)[

TypeScript

](#tab-panel-106)

CustomEditor.svelte

```
<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>
```

CustomEditor.svelte

```
<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[#](#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`:

index.js

```
export { default as CustomEditor } from './CustomEditor.svelte';
```

## Step 3: Use the Custom Editor Component[#](#step-3-use-the-custom-editor-component)

CreativeEngine only operates in the browser. To handle client-side rendering, you need to:

1.  Import the component in a route file.
2.  Render the component on a page when the app is running in the browser.

### Import the CustomEditor Component[#](#import-the-customeditor-component)

Dynamically import and render the `CustomEditor` component as follows:

1.  Open the relevant **SSR route file**, which should contain the component (for example, `src/routes/+page.svelte`).
2.  Navigate to the `<script>` section.
3.  Paste this code to **dynamically import** the `CustomEditor` component:

[

JavaScript

](#tab-panel-107)[

TypeScript

](#tab-panel-108)

+page.svelte

```
<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>
```

+page.svelte

```
<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>
```

  

The `browser` flag in `$app/environment` identifies code that only runs in the browser. For more information, visit [SvelteKit docs](https://svelte.dev/docs/kit/$app-environment#browser).

### Optional: Import Components Using the Module System[#](#optional-import-components-using-the-module-system)

If you exported `CustomEditor` from `src/lib/index.js`, you can simplify the dynamic import:

+page.svelte

```
import("$lib").then(module => {CustomEditor = module.CustomEditor;});
```

### Render the CreativeEditorSDK Component[#](#render-the-creativeeditorsdk-component)

Render the component only on the client::

1.  Navigate to the **template section** of your SvelteKit route or component
2.  **Wrap** the component like this:

+page.svelte

```
    // </script>    {#if isClient && CustomEditor}      <CustomEditor />    {/if}
```

Final `+page.svelte` file  

[

JavaScript

](#tab-panel-109)[

TypeScript

](#tab-panel-110)

+page.svelte

```
<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}
```

+page.svelte

```
<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:

1.  Navigate to the page containing `<CustomEditor>`.
2.  Check the existence of a sample image on the canvas, along with a “Reduce Opacity” button.
3.  Click the button to reduce the image’s opacity by 20% each time.

## Use Cases[#](#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[#](#troubleshooting--common-errors)

❌ **Error**: `Error when evaluating SSR module /src/routes/+page.svelte: document is not defined`

*   Verify that you integrate the `CustomEditor` component using:
    
*   Dynamic import in `/src/routes/+page.svelte`.
    
*   Client side rendering only.
    

❌ **Error**: CE.SDK canvas doesn’t render

*   Make sure you append `engine.element` to an HTML element that already exists in the page.
*   Double-check that the container element:

1.  Exists in the DOM when you call `appendChild`.
2.  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](sveltekit/get-started/new-project-without-ui-we2f7c/#step-1-install-cesdk-engine).

❌ **Error**: `Missing license key in config`

*   Ensure your `config` object:

1.  Includes a **`license` property**.
2.  You’ve set the `license` property 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[#](#next-steps)

This guide has set the stage for:

*   [Creating a full custom UI with SvelteKit.](sveltekit/user-interface/build-your-own-ui-fe7527/)
*   [Automating the export of scenes.](sveltekit/export-save-publish/export/overview-9ed3a8/)
*   [Batch processing graphics or template content.](sveltekit/automation-715209/)

---



[Source](https:/img.ly/docs/cesdk/sveltekit/get-started/new-project-w6567c)