Search
Loading...
Skip to content

Save and Export Buttons

This guide shows how to add save and export action buttons to your CE.SDK navigation bar using the Navigation Bar Order API.

Quick Start#

Add save and export buttons to your navigation bar:

import CreativeEditorSDK from '@cesdk/cesdk-js';
const cesdk = await CreativeEditorSDK.create(container, {
license: 'YOUR_CESDK_LICENSE_KEY'
});
// Add save and export buttons
cesdk.ui.insertNavigationBarOrderComponent('last', {
id: 'ly.img.actions.navigationBar',
children: [
'ly.img.saveScene.navigationBar', // Save scene
'ly.img.exportImage.navigationBar', // Export as image
'ly.img.exportPDF.navigationBar' // Export as PDF
]
});

Save Button#

The save button (ly.img.saveScene.navigationBar) persists the current scene state. You can use the default behavior or customize it.

Default Behavior#

// Adds a save button that downloads the scene file
cesdk.ui.insertNavigationBarOrderComponent('last', {
id: 'ly.img.actions.navigationBar',
children: ['ly.img.saveScene.navigationBar']
});

Custom Save with Notification#

// Register custom save callback
cesdk.actions.register('saveScene', async () => {
const scene = await cesdk.engine.scene.saveToString();
await cesdk.utils.downloadFile(scene, 'text/plain;charset=UTF-8');
cesdk.ui.showNotification('Scene saved successfully');
});
// Add save button that uses registered callback
cesdk.ui.insertNavigationBarOrderComponent('last', {
id: 'ly.img.actions.navigationBar',
children: ['ly.img.saveScene.navigationBar']
});

Save to Backend#

// Register save callback that uploads to backend
cesdk.actions.register('saveScene', async () => {
const scene = await cesdk.engine.scene.saveToString();
try {
console.log('Scene ready to save:', scene.length, 'characters');
// Production:
// const { id } = await saveProjectToBackend(scene);
// cesdk.ui.showNotification(`Saved (ID: ${id})`);
cesdk.ui.showNotification('Scene saved successfully');
} catch (error) {
cesdk.ui.showNotification('Save failed', 'error');
}
});
// Add save button that uses registered callback
cesdk.ui.insertNavigationBarOrderComponent('last', {
id: 'ly.img.actions.navigationBar',
children: ['ly.img.saveScene.navigationBar']
});

Export Buttons#

Export buttons convert your design to different output formats. CE.SDK provides three default export buttons that all trigger the exportDesign callback with different MIME types:

  • Image Export (ly.img.exportImage.navigationBar) - passes { mimeType: 'image/png' }
  • PDF Export (ly.img.exportPDF.navigationBar) - passes { mimeType: 'application/pdf' }
  • Video Export (ly.img.exportVideo.navigationBar) - passes { mimeType: 'video/mp4' }

The exportDesign callback receives the export options including the MIME type, allowing you to handle different export formats appropriately.

Image Export#

The image export button (ly.img.exportImage.navigationBar) exports the design as PNG.

Default Behavior (Download)#

Using just the string ID will download the exported PNG file to the user’s device:

// Default behavior: downloads PNG to user's device
cesdk.ui.insertNavigationBarOrderComponent('last', {
id: 'ly.img.actions.navigationBar',
children: ['ly.img.exportImage.navigationBar']
});

Upload to CDN#

// Register export callback that uploads to CDN
cesdk.actions.register('exportDesign', async (options) => {
// The options will include { mimeType: 'image/png' } from the button
const { blobs } = await cesdk.utils.export({
pngCompressionLevel: 7,
...options // This already contains mimeType: 'image/png'
});
console.log('Image ready for upload:', blobs[0].size, 'bytes');
// Production:
// const url = await uploadToCDN(blobs[0]);
cesdk.ui.showNotification('Image uploaded successfully');
});
// Add export button that uses registered callback
cesdk.ui.insertNavigationBarOrderComponent('last', {
id: 'ly.img.actions.navigationBar',
children: ['ly.img.exportImage.navigationBar']
});

PDF Export#

The PDF export button (ly.img.exportPDF.navigationBar) exports all pages as a PDF.

Default Behavior (Download)#

Using just the string ID will download the PDF file to the user’s device:

// Default behavior: downloads PDF to user's device
cesdk.ui.insertNavigationBarOrderComponent('last', {
id: 'ly.img.actions.navigationBar',
children: ['ly.img.exportPDF.navigationBar']
});

Upload to CDN#

// Register export callback that uploads PDFs to CDN
cesdk.actions.register('exportDesign', async (options) => {
// The options will include { mimeType: 'application/pdf' } from the button
const { blobs } = await cesdk.utils.export({
targetDPI: 300,
...options // This already contains mimeType: 'application/pdf'
});
console.log('PDF ready for upload:', blobs[0].size, 'bytes');
// Production:
// const url = await uploadToCDN(blobs[0]);
cesdk.ui.showNotification('PDF uploaded successfully');
});
// Add export button that uses registered callback
cesdk.ui.insertNavigationBarOrderComponent('last', {
id: 'ly.img.actions.navigationBar',
children: ['ly.img.exportPDF.navigationBar']
});

Video Export#

The video export button (ly.img.exportVideo.navigationBar) exports animations as MP4.

Default Behavior (Download)#

Using just the string ID will download the MP4 file to the user’s device:

// Default behavior: downloads MP4 to user's device
cesdk.ui.insertNavigationBarOrderComponent('last', {
id: 'ly.img.actions.navigationBar',
children: ['ly.img.exportVideo.navigationBar']
});

Upload to CDN#

// Register video export callback that uploads to CDN
cesdk.actions.register('exportDesign', async (options) => {
// The options will include { mimeType: 'video/mp4' } from the button
// Export video (utils.export handles its own loading dialog)
const { blobs } = await cesdk.utils.export({
framerate: 30,
...options // This already contains mimeType: 'video/mp4'
});
console.log('Video ready for upload:', blobs[0].size, 'bytes');
// Production:
// const url = await uploadToCDN(blobs[0]);
cesdk.ui.showNotification('Video uploaded successfully');
});
// Add export button that uses registered callback
cesdk.ui.insertNavigationBarOrderComponent('last', {
id: 'ly.img.actions.navigationBar',
children: ['ly.img.exportVideo.navigationBar']
});

Handling Multiple Export Types#

Since all export buttons trigger the same exportDesign callback with different MIME types, you can handle multiple export formats in a single callback:

// Register a unified export handler for all formats
cesdk.actions.register('exportDesign', async (exportOptions) => {
// The cesdk.utils.export automatically adapts based on the MIME type
const { blobs, options } = await cesdk.utils.export(exportOptions);
// Handle different formats using the returned options
if (options.mimeType?.startsWith('video/')) {
console.log('Video ready:', blobs[0].size, 'bytes');
// Production:
// await uploadVideoToCDN(blobs[0]);
cesdk.ui.showNotification('Video uploaded successfully');
} else if (options.mimeType === 'application/pdf') {
console.log('PDF ready:', blobs[0].size, 'bytes');
// Production:
// await uploadPDFToStorage(blobs[0]);
cesdk.ui.showNotification('PDF saved to storage');
} else {
console.log('Image ready:', blobs[0].size, 'bytes');
// Production:
// await uploadImageToCDN(blobs[0]);
cesdk.ui.showNotification('Image uploaded successfully');
}
});
// Add all export buttons - they'll all use the same callback
cesdk.ui.insertNavigationBarOrderComponent('last', {
id: 'ly.img.actions.navigationBar',
children: [
'ly.img.exportImage.navigationBar', // Passes { mimeType: 'image/png' }
'ly.img.exportPDF.navigationBar', // Passes { mimeType: 'application/pdf' }
'ly.img.exportVideo.navigationBar' // Passes { mimeType: 'video/mp4' }
]
});

Custom Export with Loading Dialogs#

When using the engine APIs directly instead of cesdk.utils.export, you need to:

  1. Create your own loading dialog using cesdk.utils.showLoadingDialog
  2. Handle the export type detection yourself based on the MIME type
  3. Manage progress updates manually

Complete Custom Export Implementation#

Use the engine API directly when you need fine-grained control over the export process. This example shows how to handle all export types (image, PDF, video) using only engine APIs:

// Register custom export using only engine APIs for full control
cesdk.actions.register('exportDesign', async (options) => {
// Create loading dialog for all export types
const dialogController = cesdk.utils.showLoadingDialog({
title: 'Exporting',
message: 'Processing your design...',
progress: 'indeterminate',
abortLabel: 'Cancel',
onAbort: () => console.log('Export cancelled')
});
try {
const page = cesdk.engine.scene.getCurrentPage();
if (page === null) {
throw new Error('No page selected for export');
}
let blob;
// Handle different export types with engine APIs
if (options?.mimeType?.startsWith('video/')) {
// Video export with progress
blob = await cesdk.engine.block.exportVideo(page, {
mimeType: options.mimeType,
targetWidth: 1920,
targetHeight: 1080,
framerate: 30,
onProgress: (rendered, encoded, total) => {
dialogController.updateProgress({
value: rendered,
max: total
});
}
});
} else {
// Static export (image, PDF)
blob = await cesdk.engine.block.export(page, {
mimeType: options?.mimeType || 'image/png',
pngCompressionLevel: 7,
targetWidth: 1920,
targetHeight: 1080
});
}
console.log('Export ready:', blob.size, 'bytes');
// Production:
// const url = await uploadToCDN(blob);
// await navigator.clipboard.writeText(url);
// Show success
dialogController.showSuccess({
message: 'Export successful'
});
} catch (error) {
// Show error
dialogController.showError({
message: 'Export failed. Please try again.'
});
}
});
// Add export button that uses registered callback
cesdk.ui.insertNavigationBarOrderComponent('last', {
id: 'ly.img.actions.navigationBar',
children: ['ly.img.exportImage.navigationBar']
});