html.to.design Electron SDK

The html.to.design Electron SDK lets you embed a Capture to Figma feature directly inside any Electron app. With a single call in your main process, users can capture whatever is rendered in your app’s window and get a Figma-ready design file — no Chrome extension required.

Dev builds only by default. The SDK is a no-op in packaged production builds unless you explicitly opt in. See Options for details.

Installation

pnpm add -D @divriots/h2d-electron-sdk

electron (≥ v22) is a peer dependency. The SDK works with npm and yarn too:

npm install --save-dev @divriots/h2d-electron-sdk
# or
yarn add -D @divriots/h2d-electron-sdk

Quick start

Save as .h2d file

Add one line to your Electron main process. A Capture to Figma toolbar appears in the bottom-right corner of every BrowserWindow in dev builds. Clicking it saves an .h2d file that can be dragged into the html.to.design Figma plugin.

import { app } from 'electron';
import { mountCapture } from '@divriots/h2d-electron-sdk';

mountCapture(app);

Copy directly to Figma

Pass an API key to skip the save-and-drag step. The toolbar will send the capture through the ‹div›RIOTS backend and write Figma-pasteable content straight to the clipboard. Users switch to Figma and press Cmd+V / Ctrl+V.

mountCapture(app, { apiKey: process.env.DIVRIOTS_API_KEY });

Mint an sk-drc-* key at divriots.com/api/settings/api-keys. Copy to Figma consumes credits from your ‹div›RIOTS ONE account.

Programmatic capture

If you want to trigger capture from your own button, menu item, or keyboard shortcut rather than the built-in toolbar, use captureWebContents directly.

Call mountCapture once first (it registers the required preload), then call captureWebContents on any trigger:

import { app, BrowserWindow, dialog } from 'electron';
import * as fs from 'fs/promises';
import { mountCapture, captureWebContents } from '@divriots/h2d-electron-sdk';

// Register the preload, but hide the built-in toolbar
mountCapture(app, { showToolbar: false });

// Save to .h2d file on demand
async function captureFocused() {
  const win = BrowserWindow.getFocusedWindow();
  if (!win) return;

  const { bytes, filename } = await captureWebContents(win.webContents);
  const { filePath } = await dialog.showSaveDialog(win, {
    defaultPath: `${filename}.h2d`,
  });
  if (filePath) await fs.writeFile(filePath, Buffer.from(bytes));
}

// Or copy directly to Figma clipboard
async function captureAndCopy() {
  const win = BrowserWindow.getFocusedWindow();
  if (!win) return;

  await captureWebContents(win.webContents, {
    copyToFigma: true,
    apiKey: process.env.DIVRIOTS_API_KEY,
  });
  // Clipboard is now populated — user pastes into Figma
}

API reference

mountCapture(app, options?)

Registers the renderer preload and optionally mounts the capture toolbar. Call once, after app is available.

OptionTypeDefaultDescription
apiKeystringprocess.env.DIVRIOTS_API_KEYAPI key for Copy to Figma.
showToolbarbooleantrueShow the built-in Capture to Figma toolbar in each window.
enabledIndev onlyOpt capture into packaged production builds. By default mountCapture no-ops when app.isPackaged is true.

captureWebContents(webContents, options?)

Captures a webContents instance and resolves with the result. mountCapture must have been called first.

OptionTypeDefaultDescription
copyToFigmabooleanfalseRoute through the backend and write Figma-pasteable content to the clipboard. Requires an API key.
apiKeystringprocess.env.DIVRIOTS_API_KEYAPI key, when copyToFigma is set.

Returns:

FieldTypeDescription
bytesUint8ArrayThe .h2d payload.
filenamestringSuggested filename (without extension).
clipboard`stringundefined`

Error handling

Copy to Figma surfaces an H2DBackendError with a human-readable .hint you can surface to users:

CodeMeaning
401Missing or invalid API key.
402Not enough credits.
import { captureWebContents, H2DBackendError } from '@divriots/h2d-electron-sdk';

try {
  await captureWebContents(win.webContents, { copyToFigma: true });
} catch (err) {
  if (err instanceof H2DBackendError) {
    showNotification(err.hint); // e.g. "Not enough credits"
  }
}

Renderer requirements

None. The SDK works with Electron’s default webPreferences. Both sandbox: true and contextIsolation: true are fully supported — the preload is bundled sandbox-compatible.

Known limitations

  • Closed shadow DOM is captured as opaque.
  • Linux clipboard: Copy to Figma works reliably on macOS and Windows. Some X11 desktop environments drop the text/html clipboard slot, which can cause Copy to Figma to fail silently.

Troubleshooting

TypeError: Cannot read properties of undefined (reading 'on')

Your shell has ELECTRON_RUN_AS_NODE=1 set, which causes the Electron binary to run as plain Node without Electron APIs. Unset it:

unset ELECTRON_RUN_AS_NODE

ℹ️ Full API reference and options are in the package README.