lucid-extensions
**Note:** This skill explicitly excludes Custom Shapes and Formulas functionality.
Install
mkdir -p .claude/skills/lucid-extensions && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/14572" && unzip -o skill.zip -d .claude/skills/lucid-extensions && rm skill.zipInstalls to .claude/skills/lucid-extensions
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
**Note:** This skill explicitly excludes Custom Shapes and Formulas functionality.About this skill
Lucid Extension Development Skill
Overview
This skill provides comprehensive guidance for building Lucid Extension Packages using the Lucid Extension API. It covers editor extensions, data connectors, OAuth providers, link unfurling, and Lucid Cards integrations for Lucidchart and Lucidspark.
Note: This skill explicitly excludes Custom Shapes and Formulas functionality.
Table of Contents
- Getting Started
- Extension Package Structure
- Editor Extensions
- Data Connectors
- OAuth Configuration
- Link Unfurling
- Lucid Cards
- Testing & Debugging
- Publishing
- Best Practices
Getting Started
Prerequisites
-
Unlock Developer Tools: Access to the Developer Menu and Developer Portal
- For Team/Enterprise accounts: Enable through user settings or contact admin
- Developer tools required to test and distribute extensions
- Not needed to use published extensions from Lucid Marketplace
-
Required Tools:
- Node.js and npm installed
lucid-packageCLI:npm install lucid-packagelucid-extension-sdk: Automatically installed with package creation
-
Important Resources:
- Developer Portal: https://lucid.app/developer
- Documentation: https://developer.lucid.co
- Sample Extensions: https://github.com/lucidsoftware/sample-lucid-extensions
- Developer Forum: https://community.lucid.co/lucid-for-developers-6
Creating a New Extension Package
# Create a new extension package
npx lucid-package@latest create
# Follow the prompts to configure:
# - Package name
# - Extension type (editor extension, data connector, etc.)
# - Target products (Lucidchart, Lucidspark, or both)
The CLI will generate a complete package structure with:
manifest.json- Package configurationeditorextensions/- Editor extension codedata-connectors/- Data connector implementations (optional)- TypeScript configurations
- Webpack configuration
Extension Package Structure
Manifest File (manifest.json)
The manifest is the central configuration file for your extension package:
{
"id": "your-package-uuid-from-developer-portal",
"version": "1.0.0",
"extensions": [
{
"name": "my-editor-extension",
"title": "My Editor Extension",
"products": ["chart", "spark"],
"codePath": "editorextensions/my-editor-extension/bin/extension.js",
"scopes": [
"READ",
"WRITE",
"SHOW_MODAL",
"CUSTOM_UI",
"NETWORK"
]
}
],
"oauthProviders": [],
"dataConnectors": []
}
Key Manifest Fields
Package Level:
id: UUID from Developer Portal (get after creating application)version: Semantic version (must increment for each upload)
Extension Entry:
name: Internal identifier (matches folder name)title: User-facing display nameproducts: Array of["chart", "spark", "teamspaces"]codePath: Path to compiled JavaScript entry pointscopes: Permission scopes required
Directory Structure
my-extension-package/
├── manifest.json
├── editorextensions/
│ └── my-extension/
│ ├── src/
│ │ ├── extension.ts # Entry point
│ │ └── importmodal.ts # Example modal
│ ├── resources/
│ │ ├── import.html # Modal HTML
│ │ └── resource.d.ts # Resource types
│ ├── public/ # Static assets (served via URL)
│ ├── bin/ # Compiled output
│ ├── package.json
│ ├── tsconfig.json
│ └── webpack.config.js
├── data-connectors/ # Optional
│ └── my-connector/
│ ├── actions/ # Action handlers
│ ├── src/
│ │ └── index.ts
│ └── debug-server.ts
└── package.json
Editor Extensions
Core Concepts
Editor extensions run custom code directly inside Lucid editors, enabling:
- Custom menus and actions
- Data import and manipulation
- Custom UI panels
- Document automation
- External API integration
Entry Point (extension.ts)
import {
EditorClient,
Menu,
MenuType,
Viewport,
Panel,
PanelLocation
} from 'lucid-extension-sdk';
// Initialize the editor client
const client = new EditorClient();
const menu = new Menu(client);
const viewport = new Viewport(client);
// Register custom actions
client.registerAction('my-action', async () => {
const selection = viewport.getSelectedItems();
// Perform operations on selected items
});
// Add menu items
menu.addDropdownMenuItem({
label: 'My Custom Action',
action: 'my-action',
menuType: MenuType.Main
});
Permission Scopes
Scopes control what your extension can access. Always request minimum scopes needed.
| Scope | Purpose | Use When |
|---|---|---|
READ | Read document contents | Analyzing shapes, reading data |
WRITE | Modify document contents | Creating/updating shapes |
DOWNLOAD | Download document data | Exporting content |
SHOW_MODAL | Display modal dialogs | User interactions, forms |
CUSTOM_UI | Create custom panels | Building right-dock panels |
NETWORK | Make network requests | API calls, data fetching |
Example scope configuration:
{
"scopes": ["READ", "WRITE", "SHOW_MODAL", "NETWORK"]
}
Custom UI Panels
Create custom panels in the right dock or left toolbox:
import { Panel, PanelLocation, EditorClient } from 'lucid-extension-sdk';
class MyPanel extends Panel {
constructor(client: EditorClient) {
super(client, {
title: 'My Panel',
iconUrl: 'https://example.com/icon.png',
location: PanelLocation.RightDock, // or PanelLocation.ContentDock
url: 'public/panel.html' // Serve from public/ directory
});
}
}
// Create panel instance
const myPanel = new MyPanel(client);
Requirements:
- Must add
CUSTOM_UIscope to manifest - Can use HTML + JavaScript or React
- Panel HTML can use iframe with relative URLs
- Static assets go in
public/directory at package root
Modals
Display modal dialogs for user input:
import { Modal } from 'lucid-extension-sdk';
const modal = new Modal(client, {
title: 'Import Data',
url: 'public/import-modal.html',
width: 600,
height: 400
});
modal.show();
Working with Document Elements
Get selected items:
const selection = viewport.getSelectedItems();
for (const item of selection) {
if (item instanceof BlockProxy) {
// Work with shapes
console.log(item.boundingBox);
}
}
Create shapes:
const page = viewport.getCurrentPage();
const block = page?.addBlock({
boundingBox: { x: 0, y: 0, w: 100, h: 100 },
style: {
fill: { color: '#ff0000' }
}
});
Modify shapes:
block.setStyle({
fill: { color: '#00ff00' },
stroke: { color: '#0000ff', width: 2 }
});
Data Management
Create data collections:
const dataSource = client.getDataSourceProxy();
const collection = dataSource.addCollection('my-collection', {
primaryKey: 'id',
fields: [
{ name: 'id', type: 'string' },
{ name: 'title', type: 'string' },
{ name: 'status', type: 'string' }
]
});
// Add data items
collection.addItem({
id: '1',
title: 'Task 1',
status: 'In Progress'
});
Link data to shapes:
block.shapeData.set('customField', 'value');
const value = block.shapeData.get('customField');
Data Connectors
When to Use Data Connectors
Use data connectors when you need:
- Bidirectional sync between Lucid and external systems
- Automatic updates from external data sources
- Push changes from Lucid back to external systems
- Server-side processing of data actions
Alternative: For simple data imports without bidirectional sync, use EditorClient.oauthXhr() directly in your editor extension.
Data Connector Architecture
Data connectors run on a separate server (not in the Lucid editor):
- Editor extension calls
client.performDataAction() - Lucid servers make POST request to your data connector
- Data connector processes request, fetches external data
- Data connector sends formatted data back to Lucid
- Lucid updates the document
Creating a Data Connector
# Create data connector
npm run create-data-connector my-connector
Manifest Configuration
{
"dataConnectors": [
{
"name": "my-connector",
"oauthProviderName": "my-oauth-provider",
"callbackBaseUrl": "https://myserver.com/connector/",
"dataActions": {
"import": "import",
"sync": "sync",
"create": "create"
}
}
]
}
Fields:
name: Internal identifieroauthProviderName: Associated OAuth provider for authenticationcallbackBaseUrl: Base URL where your connector is hosteddataActions: Maps action names to URL suffixes
Implementing Data Actions
Editor Extension Trigger:
client.performDataAction({
dataConnectorName: 'my-connector',
actionName: 'import',
actionData: { requestedItems: ['id-1', 'id-2'] },
asynchronous: true
});
Data Connector Handler (actions/import.ts):
import { DataConnectorClient } from 'lucid-extension-sdk';
export async function handleImport(
request: DataAction,
client: DataConnectorClient
) {
const { actionData, oauthToken } = request;
// Fetch data from external API using OAuth token
const externalData = await fetchFromExternalAPI(
oauthToken,
actionData.requestedItems
);
// Transform to Lucid format
const lucidData = transformData(externalData);
// Send to Lucid
await client.sendDataUpdate(request.dataUpda
---
*Content truncated.*