Search Docs
Loading...
Skip to content

Export to Figma

Export a CE.SDK scene as a Figma file with a frame for each page.

6 mins
estimated time
Download

The @imgly/figma-exporter package runs in Node.js 22.15 or later (23.x requires 23.8+) alongside @cesdk/node. It converts scenes created in CE.SDK as well as scenes imported from Figma. Figma-specific metadata is optional.

The downloadable recipe creates a two-page design, writes source PNGs, and saves output/design.fig with a diagnostics report. Run it with its dev script. Set FIGMA_SOURCE_ARCHIVE to a local .imgly path to export an existing design instead.

This guide covers scene preparation, source previews, file export, diagnostics, and verification in Figma.

Import the Package and Initialize the Engine#

Install @imgly/figma-exporter alongside @cesdk/node and import exportFig().

import { exportFig } from '@imgly/figma-exporter';

We load optional environment variables and initialize the engine. To use your CE.SDK license, set CESDK_LICENSE and uncomment the license setting.

config();
const engine = await CreativeEngine.init({
// license: process.env.CESDK_LICENSE,
baseURL: process.env.IMGLY_LOCAL_ASSETS_URL
});

Prepare the Scene#

The default example creates two pages with named, editable rectangles. These pages require no Figma source data or external design assets.

const scene = engine.scene.create();
engine.block.setName(scene, 'Two-page design');
for (let index = 0; index < 2; index++) {
const page = engine.block.create('page');
engine.block.setName(page, `Page ${index + 1}`);
engine.block.setWidth(page, 600);
engine.block.setHeight(page, 400);
engine.block.appendChild(scene, page);
const graphic = engine.block.create('graphic');
engine.block.setName(graphic, `Rectangle ${index + 1}`);
engine.block.setShape(graphic, engine.block.createShape('rect'));
const fill = engine.block.createFill('color');
engine.block.setColor(fill, 'fill/color/value', {
r: index === 0 ? 0.2 : 0.9,
g: 0.4,
b: index === 0 ? 0.8 : 0.2,
a: 1
});
engine.block.setFill(graphic, fill);
engine.block.setWidth(graphic, 400);
engine.block.setHeight(graphic, 200);
engine.block.setPositionX(graphic, 100);
engine.block.setPositionY(graphic, 100);
engine.block.appendChild(page, graphic);
}

For an existing design, read its archive and load it while waiting for resources. The recipe takes this path when FIGMA_SOURCE_ARCHIVE is configured.

const bytes = await readFile(archivePath);
await engine.scene.loadFromArchiveURL(
`data:application/zip;base64,${bytes.toString('base64')}`,
false,
true
);

The exporter accepts engine versions from 1.81.1. This peer range describes API compatibility; rendering also depends on the installed engine version, fonts, and available resources.

Save Source Previews#

We render each CE.SDK page to a PNG beside the export. These files provide a reference for the recipient, but they do not verify how Figma displays the exported file.

const outputDir = new URL('./output/', import.meta.url);
await mkdir(outputDir, { recursive: true });
for (const [index, page] of engine.scene.getPages().entries()) {
const preview = await engine.block.export(page, {
mimeType: 'image/png'
});
await writeFile(
new URL(`page-${index + 1}-source.png`, outputDir),
new Uint8Array(await preview.arrayBuffer())
);
}

Export the File#

Call exportFig() with the loaded engine and write the returned Uint8Array. fileName sets the name stored in the Figma file metadata. You can also supply PNG bytes through the optional thumbnail setting.

const { fig, logger } = await exportFig(engine, {
fileName: 'CE.SDK design'
});
await writeFile(new URL('design.fig', outputDir), fig);

One scene becomes one Figma canvas. Each CE.SDK page becomes a named frame carrying its finite dimensions, fill, and clipping behavior. A multi-page scene therefore produces one .fig file.

Review Conversion Notes#

Save logger.getMessages() and inspect the messages before handoff. Each message has a severity, code, and description.

const messages = logger.getMessages();
await writeFile(
new URL('export-report.json', outputDir),
JSON.stringify({ messages }, null, 2)
);
for (const message of messages) {
console.warn(`${message.type}: ${message.code} — ${message.message}`);
}

Supported text, shapes, images, gradients, strokes, and effects remain editable. Graphics that need a rendered-image fallback produce BLOCK_RASTERIZED. Unsupported block types are skipped with UNSUPPORTED_BLOCK_TYPE. Rendering failures and other approximations have their own diagnostics.

The companion importer preserves available source-specific properties as x-figma/… metadata. Current engine state controls mapped properties, while supported metadata restores unmapped properties. Text sizing edits override an older preserved autosizing mode. This is best-effort preservation; it does not guarantee an identical Figma file or render. Fonts required by editable text must be available in Figma.

Verify in Figma#

Import output/design.fig through Figma’s file browser and open it in the editor. Compare every page frame with the corresponding source PNG, including text, fonts, images, stacking, and clipping.

Figma computes text layout when a file opens. A REST render requested before that step can omit text. A local import/export loop can agree with itself while reproducing the wrong appearance, so inspect the result in Figma.

Figma’s REST API reads design content but provides no endpoint to upload a .fig or write the scene’s design nodes. Opening the file in Figma is a separate application step.

For browser editing, save an .imgly archive in the browser, send it to a Node endpoint, and return the exported .fig bytes. The exporter uses Node modules and cannot load directly in a browser bundle.

Dispose the Engine#

Use finally to release the engine even when loading, rendering, exporting, or saving fails.

engine.dispose();

Troubleshooting#

The package fails to load in a browser — Run conversion in Node.js and exchange archives with the browser editor.

Text is absent from a REST render — Open the imported file in Figma’s editor before requesting its render. Check missing-font messages when text still differs.

An object is no longer editable or is missing — Review the diagnostics for raster fallbacks, unsupported block types, and rendering failures.

The source PNG looks correct but Figma differs — The PNG renders CE.SDK content. Verify the .fig in Figma with the required fonts and review each conversion note.

API Reference#

Method / Result Description
CreativeEngine.init(config) Initialize the Node engine
engine.scene.create() Create the default source design
engine.scene.loadFromArchiveURL(url, false, true) Load an archive and await resources
engine.scene.getPages() Enumerate source pages
engine.block.export(page, { mimeType: 'image/png' }) Render a source preview
exportFig(engine, { fileName, thumbnail }) Return .fig bytes and a logger
logger.getMessages() Read typed conversion diagnostics
engine.dispose() Release engine resources

Next Steps#

Use Import From Figma to bring local files or REST content into CE.SDK before editing and exporting.