Build reusable design templates entirely through code using CE.SDK’s programmatic APIs for automation, batch generation, and custom template creation tools.
CE.SDK provides a complete API for building design templates through code. Instead of starting from an existing template, you can create a blank scene, define page dimensions, add text and graphic blocks, configure placeholders for swappable media, add text variables for dynamic content, apply editing constraints to protect layout integrity, and save the template for reuse. This approach enables automation workflows, batch template generation, and integration with custom template creation tools.
This guide covers how to create a blank scene, add text blocks with variables, add image placeholders, apply editing constraints, and save the template.
Initialize CE.SDK#
We start by initializing CE.SDK’s Node.js engine for server-side rendering and scene manipulation.
const engine = await CreativeEngine.init({ // license: process.env.CESDK_LICENSE});Create a Blank Scene#
We create the foundation of our template with custom page dimensions. The engine.scene.create() method accepts page options to set width, height, and background color.
// Template layout constants for a promotional cardconst CANVAS_WIDTH = 800;const CANVAS_HEIGHT = 1000;const PADDING = 40;const CONTENT_WIDTH = CANVAS_WIDTH - PADDING * 2;
// Create a blank scene with custom dimensionsengine.scene.create('Free', { page: { size: { width: CANVAS_WIDTH, height: CANVAS_HEIGHT } }});
// Set design unit to Pixel for precise coordinate mappingengine.scene.setDesignUnit('Pixel');The scene creation method accepts a layout mode ('Free' for design mode) and optional page configuration. When options are provided, the scene automatically includes a page with the specified dimensions.
Set Page Background#
We set a light background color to give the template a consistent base appearance.
// Set a gradient background for the templateconst backgroundFill = engine.block.createFill('gradient/linear');engine.block.setGradientColorStops(backgroundFill, 'fill/gradient/colors', [ { color: { r: 0.4, g: 0.2, b: 0.6, a: 1.0 }, stop: 0 }, // Purple { color: { r: 0.2, g: 0.4, b: 0.8, a: 1.0 }, stop: 1 } // Blue]);engine.block.setFill(page, backgroundFill);We create a color fill using engine.block.createFill('color'), set the color via engine.block.setColor() with the fill/color/value property, then assign the fill to the page using engine.block.setFill().
Add Text Blocks#
Text blocks allow you to add styled text content. We create a headline that includes a variable token for dynamic content.
// Create headline text block with {{title}} variableconst headline = engine.block.create('text');engine.block.replaceText(headline, '{{title}}');
// Set font with proper typeface for consistent renderingengine.block.setFont(headline, FONT_BOLD, { name: 'Roboto', fonts: [{ uri: FONT_BOLD, subFamily: 'Bold', weight: 'bold' }]});engine.block.setFloat(headline, 'text/fontSize', 28);engine.block.setTextColor(headline, { r: 1.0, g: 1.0, b: 1.0, a: 1.0 });
// Position and size the headlineengine.block.setWidthMode(headline, 'Absolute');engine.block.setHeightMode(headline, 'Auto');engine.block.setWidth(headline, CONTENT_WIDTH);engine.block.setPositionX(headline, PADDING);engine.block.setPositionY(headline, 50);engine.block.setEnum(headline, 'text/horizontalAlignment', 'Center');engine.block.appendChild(page, headline);We create a text block using engine.block.create('text'), set its content with engine.block.replaceText(), configure dimensions and position, and append it to the page using engine.block.appendChild().
Add Text Variables#
Text variables enable data-driven personalization. By using {{variableName}} tokens in text blocks, you can populate content programmatically.
// Set default value for the title variableengine.variable.setString('title', 'Summer Sale');The engine.variable.setString() method sets the default value for the variable. When the template is used, this value can be changed to personalize the content.
Add Graphic Blocks#
Graphic blocks serve as containers for images. We create an image block that will become a placeholder for swappable media.
// Create image placeholder in the center of the cardconst imageBlock = engine.block.create('graphic');const imageShape = engine.block.createShape('rect');engine.block.setShape(imageBlock, imageShape);
const imageFill = engine.block.createFill('image');engine.block.setString( imageFill, 'fill/image/imageFileURI', 'https://img.ly/static/ubq_samples/sample_1.jpg');engine.block.setFill(imageBlock, imageFill);
engine.block.setWidth(imageBlock, CONTENT_WIDTH);engine.block.setHeight(imageBlock, 420);engine.block.setPositionX(imageBlock, PADDING);engine.block.setPositionY(imageBlock, 295);engine.block.appendChild(page, imageBlock);We create a graphic block with engine.block.create('graphic'), assign a rectangle shape using engine.block.createShape('rect') and engine.block.setShape(), create an image fill with engine.block.createFill('image'), set the image URI via engine.block.setString(), and position it on the page.
Configure Placeholders#
Placeholders turn design blocks into drop-zones where users can swap content while maintaining layout integrity. We enable placeholder behavior on the image fill and configure visual controls.
// Enable placeholder behavior on the image fillconst fill = engine.block.getFill(imageBlock);if (fill !== null && engine.block.supportsPlaceholderBehavior(fill)) { engine.block.setPlaceholderBehaviorEnabled(fill, true);}engine.block.setPlaceholderEnabled(imageBlock, true);
// Enable visual controls for the placeholderengine.block.setPlaceholderControlsOverlayEnabled(imageBlock, true);engine.block.setPlaceholderControlsButtonEnabled(imageBlock, true);Placeholder behavior is enabled on the fill (not the block) for graphic blocks. We also enable the overlay pattern and replace button for visual guidance.
Apply Editing Constraints#
Editing constraints protect template elements by restricting what users can modify. We use scopes to lock position and size while allowing content changes.
// Set global scope to 'Defer' for per-block controlengine.editor.setGlobalScope('layer/move', 'Defer');engine.editor.setGlobalScope('layer/resize', 'Defer');
// Lock all text block positions but allow text editingconst textBlocks = [headline, subheadline, cta];textBlocks.forEach((block) => { engine.block.setScopeEnabled(block, 'layer/move', false); engine.block.setScopeEnabled(block, 'layer/resize', false);});
// Lock image position but allow fill replacementengine.block.setScopeEnabled(imageBlock, 'layer/move', false);engine.block.setScopeEnabled(imageBlock, 'layer/resize', false);engine.block.setScopeEnabled(imageBlock, 'fill/change', true);Setting global scope to 'Defer' enables per-block control. We then disable movement and resizing for both blocks while enabling fill changes for the image placeholder.
Save the Template#
We persist the template in two formats: a lightweight string for CDN-hosted assets and a self-contained archive with embedded assets.
// Prompt utility for interactive save optionsfunction prompt(question: string): Promise<string> { const rl = createInterface({ input: process.stdin, output: process.stdout });
return new Promise((resolve) => { rl.question(question, (answer) => { rl.close(); resolve(answer); }); });}
async function main() { // Display save options menu console.log('=== Template Save Options ===\n'); console.log('1. Save as string (for CDN-hosted assets)'); console.log('2. Save as archive (self-contained ZIP)'); console.log('3. Export as PNG image'); console.log('4. Save all formats and export png\n');
const choice = (await prompt('Select save option (1-4): ')) || '4';The engine.scene.saveToString() method creates a compact string format suitable for storage when assets are hosted externally. The engine.scene.saveToArchive() method creates a ZIP bundle containing all assets, ideal for offline use or distribution.
Cleanup#
We dispose of the engine to release resources when processing is complete.
engine.dispose();Troubleshooting#
- Blocks not appearing: Verify that
engine.block.appendChild()attaches blocks to the page. Blocks must be part of the scene hierarchy to render. - Variables not resolving: Verify the variable name in the text matches exactly, including curly braces syntax
{{variableName}}. - Placeholder not interactive: Ensure
engine.block.setPlaceholderEnabled()is called on the block and the appropriate scope (fill/change) is enabled. - Constraints not enforced: Verify
engine.editor.setGlobalScope()is set to'Defer'before setting per-block scopes.
API Reference#
| Method | Description |
|---|---|
engine.scene.create() | Create a new design scene with optional page size |
engine.scene.setDesignUnit() | Set the design unit (Pixel, Millimeter, Inch) |
engine.scene.saveToString() | Save scene to string format |
engine.scene.saveToArchive() | Save scene to ZIP archive |
engine.block.create() | Create a design block (page, text, graphic) |
engine.block.appendChild() | Append a child block to a parent |
engine.block.findByType() | Find blocks by their type |
engine.block.createFill() | Create a fill (color, image, etc.) |
engine.block.setFill() | Assign a fill to a block |
engine.block.getFill() | Get the fill of a block |
engine.block.createShape() | Create a shape (rect, ellipse, etc.) |
engine.block.setShape() | Assign a shape to a graphic block |
engine.block.setString() | Set a string property on a block |
engine.block.setColor() | Set a color property |
engine.block.replaceText() | Set text content |
engine.block.setFont() | Set font with typeface |
engine.block.setPlaceholderBehaviorEnabled() | Enable placeholder behavior on fill |
engine.block.setPlaceholderEnabled() | Enable placeholder interaction on block |
engine.block.setPlaceholderControlsOverlayEnabled() | Enable overlay visual control |
engine.block.setPlaceholderControlsButtonEnabled() | Enable button visual control |
engine.variable.setString() | Set a text variable value |
engine.editor.setGlobalScope() | Set global scope permission |
engine.block.setScopeEnabled() | Enable/disable scope on a block |
Next Steps#
- Placeholders - Configure placeholder behavior and visual controls in depth
- Text Variables - Implement dynamic text personalization with variables
- Set Editing Constraints - Lock layout properties to protect design integrity
- Add to Template Library - Register templates in the asset library for users to discover