# Programmatic Creation

Build compositions entirely through code using CE.SDK’s APIs for automation, batch processing, and custom interfaces.

![Programmatic Creation](/docs/cesdk/_astro/browser.hero.Bv_VUfSd_5eHec.webp)

10 mins

estimated time

Live Demo[

Download](https://github.com/imgly/cesdk-web-examples/archive/refs/heads/main.zip)[

StackBlitz](https://stackblitz.com/~/github.com/imgly/cesdk-web-examples/tree/main/guides-create-composition-programmatic-browser)[

GitHub](https://github.com/imgly/cesdk-web-examples/tree/main/guides-create-composition-programmatic-browser)

CE.SDK provides a complete API for building designs through code. Instead of relying on user interactions through the built-in UI, you can create scenes, add blocks like text, images, and shapes, and position them programmatically. This approach enables automation workflows, batch processing, server-side rendering, and integration with custom interfaces.

```
import type { EditorPlugin, EditorPluginContext } from '@cesdk/cesdk-js';import packageJson from './package.json';
/** * CE.SDK Plugin: Programmatic Creation Guide * * Demonstrates building compositions entirely through code: * - Creating scenes and pages with social media dimensions * - Setting page background colors * - Adding text blocks with mixed styling (bold, italic, colors) * - Adding line shapes as dividers * - Adding images * - Positioning and sizing blocks */
// Roboto typeface with all variants for mixed stylingconst ROBOTO_TYPEFACE = {  name: 'Roboto',  fonts: [    {      uri: 'https://cdn.img.ly/assets/v2/ly.img.typeface/fonts/Roboto/Roboto-Regular.ttf',      subFamily: 'Regular'    },    {      uri: 'https://cdn.img.ly/assets/v2/ly.img.typeface/fonts/Roboto/Roboto-Bold.ttf',      subFamily: 'Bold',      weight: 'bold' as const    },    {      uri: 'https://cdn.img.ly/assets/v2/ly.img.typeface/fonts/Roboto/Roboto-Italic.ttf',      subFamily: 'Italic',      style: 'italic' as const    },    {      uri: 'https://cdn.img.ly/assets/v2/ly.img.typeface/fonts/Roboto/Roboto-BoldItalic.ttf',      subFamily: 'Bold Italic',      weight: 'bold' as const,      style: 'italic' as const    }  ]};
class Example implements EditorPlugin {  name = packageJson.name;
  version = packageJson.version;
  async initialize({ cesdk }: EditorPluginContext): Promise<void> {    if (!cesdk) {      throw new Error('CE.SDK instance is required for this plugin');    }
    // Initialize CE.SDK with Design mode and load asset sources    await cesdk.addDefaultAssetSources();    await cesdk.addDemoAssetSources({      sceneMode: 'Design',      withUploadAssetSources: true    });
    const engine = cesdk.engine;
    // Create a new scene with social media dimensions (1080x1080)    await cesdk.createDesignScene();    const scene = engine.scene.get()!;
    engine.block.setFloat(scene, 'scene/dpi', 300);    const page = engine.block.findByType('page')[0];    engine.block.setWidth(page, 1080);    engine.block.setHeight(page, 1080);
    // Set page background to light lavender color    const backgroundFill = engine.block.createFill('color');    engine.block.setColor(backgroundFill, 'fill/color/value', {      r: 0.94,      g: 0.93,      b: 0.98,      a: 1.0    });    engine.block.setFill(page, backgroundFill);
    // Add main headline text with bold Roboto font    const headline = engine.block.create('text');    engine.block.replaceText(      headline,      'Integrate\nCreative Editing\ninto your App'    );    engine.block.setFont(      headline,      ROBOTO_TYPEFACE.fonts[0].uri,      ROBOTO_TYPEFACE    );    engine.block.setFloat(headline, 'text/lineHeight', 0.78);
    // Make headline bold    if (engine.block.canToggleBoldFont(headline)) {      engine.block.toggleBoldFont(headline);    }    engine.block.setTextColor(headline, { r: 0.0, g: 0.0, b: 0.0, a: 1.0 });
    // Set fixed container size and enable automatic font sizing    engine.block.setWidthMode(headline, 'Absolute');    engine.block.setHeightMode(headline, 'Absolute');    engine.block.setWidth(headline, 960);    engine.block.setHeight(headline, 300);    engine.block.setBool(headline, 'text/automaticFontSizeEnabled', true);
    engine.block.setPositionX(headline, 60);    engine.block.setPositionY(headline, 80);    engine.block.appendChild(page, headline);
    // Add tagline with mixed styling using range-based APIs    // "in hours," (purple italic) + "not months." (black bold)    const tagline = engine.block.create('text');    const taglineText = 'in hours,\nnot months.';    engine.block.replaceText(tagline, taglineText);
    // Set up Roboto typeface with all variants for mixed styling    engine.block.setFont(      tagline,      ROBOTO_TYPEFACE.fonts[0].uri,      ROBOTO_TYPEFACE    );    engine.block.setFloat(tagline, 'text/lineHeight', 0.78);
    // Style "in hours," - purple and italic (characters 0-9)    engine.block.setTextColor(      tagline,      { r: 0.2, g: 0.2, b: 0.8, a: 1.0 },      0,      9    );    if (engine.block.canToggleItalicFont(tagline, 0, 9)) {      engine.block.toggleItalicFont(tagline, 0, 9);    }
    // Style "not months." - black and bold (characters 10-21)    engine.block.setTextColor(      tagline,      { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },      10,      21    );    if (engine.block.canToggleBoldFont(tagline, 10, 21)) {      engine.block.toggleBoldFont(tagline, 10, 21);    }
    // Set fixed container size and enable automatic font sizing    engine.block.setWidthMode(tagline, 'Absolute');    engine.block.setHeightMode(tagline, 'Absolute');    engine.block.setWidth(tagline, 960);    engine.block.setHeight(tagline, 220);    engine.block.setBool(tagline, 'text/automaticFontSizeEnabled', true);    engine.block.setPositionX(tagline, 60);    engine.block.setPositionY(tagline, 551);    engine.block.appendChild(page, tagline);
    // Add CTA text "Start a Free Trial" with bold font    const ctaTitle = engine.block.create('text');    engine.block.replaceText(ctaTitle, 'Start a Free Trial');    engine.block.setFont(      ctaTitle,      ROBOTO_TYPEFACE.fonts[0].uri,      ROBOTO_TYPEFACE    );    engine.block.setFloat(ctaTitle, 'text/fontSize', 80);    engine.block.setFloat(ctaTitle, 'text/lineHeight', 1.0);
    if (engine.block.canToggleBoldFont(ctaTitle)) {      engine.block.toggleBoldFont(ctaTitle);    }    engine.block.setTextColor(ctaTitle, { r: 0.0, g: 0.0, b: 0.0, a: 1.0 });
    engine.block.setWidthMode(ctaTitle, 'Absolute');    engine.block.setHeightMode(ctaTitle, 'Auto');    engine.block.setWidth(ctaTitle, 664.6);    engine.block.setPositionX(ctaTitle, 64);    engine.block.setPositionY(ctaTitle, 952);    engine.block.appendChild(page, ctaTitle);
    // Add website URL with regular font    const ctaUrl = engine.block.create('text');    engine.block.replaceText(ctaUrl, 'www.img.ly');    engine.block.setFont(ctaUrl, ROBOTO_TYPEFACE.fonts[0].uri, ROBOTO_TYPEFACE);    engine.block.setFloat(ctaUrl, 'text/fontSize', 80);    engine.block.setFloat(ctaUrl, 'text/lineHeight', 1.0);    engine.block.setTextColor(ctaUrl, { r: 0.0, g: 0.0, b: 0.0, a: 1.0 });
    engine.block.setWidthMode(ctaUrl, 'Absolute');    engine.block.setHeightMode(ctaUrl, 'Auto');    engine.block.setWidth(ctaUrl, 664.6);    engine.block.setPositionX(ctaUrl, 64);    engine.block.setPositionY(ctaUrl, 1006);    engine.block.appendChild(page, ctaUrl);
    // Add horizontal divider line    const dividerLine = engine.block.create('graphic');    const lineShape = engine.block.createShape('line');    engine.block.setShape(dividerLine, lineShape);
    const lineFill = engine.block.createFill('color');    engine.block.setColor(lineFill, 'fill/color/value', {      r: 0.0,      g: 0.0,      b: 0.0,      a: 1.0    });    engine.block.setFill(dividerLine, lineFill);
    engine.block.setWidth(dividerLine, 418);    engine.block.setHeight(dividerLine, 11.3);    engine.block.setPositionX(dividerLine, 64);    engine.block.setPositionY(dividerLine, 460);    engine.block.appendChild(page, dividerLine);
    // Add IMG.LY logo image    const logo = engine.block.create('graphic');    const logoShape = engine.block.createShape('rect');    engine.block.setShape(logo, logoShape);
    const logoFill = engine.block.createFill('image');    engine.block.setString(      logoFill,      'fill/image/imageFileURI',      'https://img.ly/static/ubq_samples/imgly_logo.jpg'    );    engine.block.setFill(logo, logoFill);
    engine.block.setContentFillMode(logo, 'Contain');    engine.block.setWidth(logo, 200);    engine.block.setHeight(logo, 65);    engine.block.setPositionX(logo, 820);    engine.block.setPositionY(logo, 960);    engine.block.appendChild(page, logo);
    // Export the composition to PNG    const blob = await engine.block.export(page, {      mimeType: 'image/png',      targetWidth: 1080,      targetHeight: 1080    });
    // In browser, create a download link    const url = URL.createObjectURL(blob);    console.log('Export complete. Download URL:', url);
    // Zoom to show the page    await cesdk.actions.run('zoom.toPage', { autoFit: true });  }}
export default Example;
```

This guide covers how to create a scene structure with social media dimensions, set background colors, add text with mixed styling, line shapes, images, and export the finished composition.

## Initialize CE.SDK[#](#initialize-cesdk)

We start by initializing CE.SDK and loading the asset sources. The `cesdk.addDefaultAssetSources()` and `cesdk.addDemoAssetSources()` methods provide access to fonts, images, and other assets.

```
// Initialize CE.SDK with Design mode and load asset sourcesawait cesdk.addDefaultAssetSources();await cesdk.addDemoAssetSources({  sceneMode: 'Design',  withUploadAssetSources: true});
const engine = cesdk.engine;
```

## Create Scene Structure[#](#create-scene-structure)

We create the foundation of our composition with social media dimensions (1080x1080 pixels for Instagram). A scene contains one or more pages, and pages contain the design blocks.

```
// Create a new scene with social media dimensions (1080x1080)await cesdk.createDesignScene();const scene = engine.scene.get()!;
```

The `cesdk.createDesignScene()` method creates a new design scene with a page. We set the page dimensions using `setWidth()` and `setHeight()`.

## Set Page Background[#](#set-page-background)

We set the page background using a color fill. This demonstrates how to create and assign fills to blocks.

```
// Set page background to light lavender colorconst backgroundFill = engine.block.createFill('color');engine.block.setColor(backgroundFill, 'fill/color/value', {  r: 0.94,  g: 0.93,  b: 0.98,  a: 1.0});engine.block.setFill(page, backgroundFill);
```

We create a color fill using `createFill('color')`, set the color via `setColor()` with the `fill/color/value` property, then assign the fill to the page.

## Add Text Blocks[#](#add-text-blocks)

Text blocks allow you to add and style text content. We demonstrate three different approaches to text sizing and styling.

### Create Text and Set Content[#](#create-text-and-set-content)

Create a text block and set its content with `replaceText()`:

```
// Add main headline text with bold Roboto fontconst headline = engine.block.create('text');engine.block.replaceText(  headline,  'Integrate\nCreative Editing\ninto your App');engine.block.setFont(  headline,  ROBOTO_TYPEFACE.fonts[0].uri,  ROBOTO_TYPEFACE);engine.block.setFloat(headline, 'text/lineHeight', 0.78);
```

### Style Entire Text Block[#](#style-entire-text-block)

Apply styling to the entire text block using `toggleBoldFont()` and `setTextColor()`:

```
// Make headline boldif (engine.block.canToggleBoldFont(headline)) {  engine.block.toggleBoldFont(headline);}engine.block.setTextColor(headline, { r: 0.0, g: 0.0, b: 0.0, a: 1.0 });
```

### Enable Automatic Font Sizing[#](#enable-automatic-font-sizing)

Configure the text block to automatically scale its font size to fit within fixed dimensions:

```
// Set fixed container size and enable automatic font sizingengine.block.setWidthMode(headline, 'Absolute');engine.block.setHeightMode(headline, 'Absolute');engine.block.setWidth(headline, 960);engine.block.setHeight(headline, 300);engine.block.setBool(headline, 'text/automaticFontSizeEnabled', true);
```

### Range-based Text Styling[#](#range-based-text-styling)

Apply different styles to specific character ranges within a single text block:

```
// Style "in hours," - purple and italic (characters 0-9)engine.block.setTextColor(  tagline,  { r: 0.2, g: 0.2, b: 0.8, a: 1.0 },  0,  9);if (engine.block.canToggleItalicFont(tagline, 0, 9)) {  engine.block.toggleItalicFont(tagline, 0, 9);}
// Style "not months." - black and bold (characters 10-21)engine.block.setTextColor(  tagline,  { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },  10,  21);if (engine.block.canToggleBoldFont(tagline, 10, 21)) {  engine.block.toggleBoldFont(tagline, 10, 21);}
```

The range-based APIs accept start and end character indices:

*   `setTextColor(id, color, from, to)` - Apply color to a specific character range
*   `toggleBoldFont(id, from, to)` - Toggle bold styling for a range
*   `toggleItalicFont(id, from, to)` - Toggle italic styling for a range

### Fixed Font Size[#](#fixed-font-size)

Set an explicit font size instead of using auto-sizing:

```
// Add CTA text "Start a Free Trial" with bold fontconst ctaTitle = engine.block.create('text');engine.block.replaceText(ctaTitle, 'Start a Free Trial');engine.block.setFont(  ctaTitle,  ROBOTO_TYPEFACE.fonts[0].uri,  ROBOTO_TYPEFACE);engine.block.setFloat(ctaTitle, 'text/fontSize', 80);engine.block.setFloat(ctaTitle, 'text/lineHeight', 1.0);
```

## Add Shapes[#](#add-shapes)

We create shapes using graphic blocks. CE.SDK supports `rect`, `line`, `ellipse`, `polygon`, `star`, and `vector_path` shapes.

### Create a Shape Block[#](#create-a-shape-block)

Create a graphic block and assign a shape to it:

```
// Add horizontal divider lineconst dividerLine = engine.block.create('graphic');const lineShape = engine.block.createShape('line');engine.block.setShape(dividerLine, lineShape);
```

### Apply Fill to Shape[#](#apply-fill-to-shape)

Create a color fill and apply it to the shape:

```
const lineFill = engine.block.createFill('color');engine.block.setColor(lineFill, 'fill/color/value', {  r: 0.0,  g: 0.0,  b: 0.0,  a: 1.0});engine.block.setFill(dividerLine, lineFill);
```

## Add Images[#](#add-images)

We add images using graphic blocks with image fills.

### Create an Image Block[#](#create-an-image-block)

Create a graphic block with a rect shape and an image fill:

```
// Add IMG.LY logo imageconst logo = engine.block.create('graphic');const logoShape = engine.block.createShape('rect');engine.block.setShape(logo, logoShape);
const logoFill = engine.block.createFill('image');engine.block.setString(  logoFill,  'fill/image/imageFileURI',  'https://img.ly/static/ubq_samples/imgly_logo.jpg');engine.block.setFill(logo, logoFill);
```

We set the image URL via `setString()` with the `fill/image/imageFileURI` property.

## Position and Size Blocks[#](#position-and-size-blocks)

All blocks use the same positioning and sizing APIs:

```
engine.block.setContentFillMode(logo, 'Contain');engine.block.setWidth(logo, 200);engine.block.setHeight(logo, 65);engine.block.setPositionX(logo, 820);engine.block.setPositionY(logo, 960);engine.block.appendChild(page, logo);
```

*   `setWidth()` / `setHeight()` - Set block dimensions
*   `setPositionX()` / `setPositionY()` - Set block position
*   `setContentFillMode()` - Control how content fills the block (`Contain`, `Cover`, `Crop`)
*   `appendChild()` - Add the block to the page hierarchy

## Export the Composition[#](#export-the-composition)

CE.SDK provides two approaches for exporting compositions in browser environments.

### Export Using the Engine API[#](#export-using-the-engine-api)

The `engine.block.export()` method exports a block as a blob that you can use programmatically:

```
// Export the composition to PNGconst blob = await engine.block.export(page, {  mimeType: 'image/png',  targetWidth: 1080,  targetHeight: 1080});
// In browser, create a download linkconst url = URL.createObjectURL(blob);console.log('Export complete. Download URL:', url);
```

In browser environments, you can create a download URL from the blob using `URL.createObjectURL()`.

### Export Using Built-in Actions[#](#export-using-built-in-actions)

Alternatively, use the built-in export panel or actions for a complete export dialog:

```
await cesdk.actions.run('exportDesign', {  mimeType: 'image/png'});
```

The export panel lets users choose format and settings interactively, while `cesdk.actions.run('export.page', options)` triggers export directly with specified options.

## Troubleshooting[#](#troubleshooting)

*   **Blocks not appearing**: Verify that `appendChild()` attaches blocks to the page. Blocks must be part of the scene hierarchy to render.
*   **Text styling not applied**: Verify character indices are correct for range-based APIs. The indices are UTF-16 based.
*   **Image stretched**: Use `setContentFillMode(block, 'Contain')` to maintain the image’s aspect ratio.
*   **Export fails**: Verify that page dimensions are set before export. The export requires valid dimensions.

## Next Steps[#](#next-steps)

*   [Layer Management](sveltekit/create-composition/layer-management-18f07a/) \- Control block stacking and organization
*   [Positioning and Alignment](sveltekit/insert-media/position-and-align-cc6b6a/) \- Precise block placement
*   [Group and Ungroup](sveltekit/create-composition/group-and-ungroup-62565a/) \- Group blocks for unified transforms
*   [Blend Modes](sveltekit/create-composition/blend-modes-ad3519/) \- Control how blocks interact visually
*   [Export](sveltekit/export-save-publish/export-82f968/) \- Export options and formats

---



[Source](https:/img.ly/docs/cesdk/sveltekit/create-composition/multi-page-4d2b50)