` element to display a color swatch.
@@ -296,6 +415,10 @@ addOnUISdk.ready.then(async () => {
To use the picked color in the Document Sandbox, you can use the [`colorUtils.fromHex()`](../../../references/document-sandbox/document-apis/classes/ColorUtils.md#fromhex) method, which converts the HEX color string to a [`Color`](../../../references/document-sandbox/document-apis/interfaces/Color.md) object.
+
+
+#### JavaScript
+
```js
// sandbox/code.js
const color = colorUtils.fromHex(event.detail.color); // π A Color object
@@ -308,6 +431,20 @@ if (selection.length === 1 && selection[0].type === "Text") {
}
```
+#### TypeScript
+
+```ts
+// sandbox/code.js
+const color: Color = colorUtils.fromHex(event.detail.color); // π A Color object
+
+// Use the color in the Document Sandbox, for example:
+let selection = editor.context.selection;
+if (selection.length === 1 && selection[0].type === "Text") {
+ const textContentModel = (selection[0] as TextNode).fullContent;
+ textContentModel.applyCharacterStyles({ color }); // π Using the color
+}
+```
+
## FAQs
#### Q: How do I create colors from RGB values?
diff --git a/src/pages/guides/learn/how_to/use_geometry.md b/src/pages/guides/learn/how_to/use_geometry.md
index e5c5a5d8b..7a25a7a61 100644
--- a/src/pages/guides/learn/how_to/use_geometry.md
+++ b/src/pages/guides/learn/how_to/use_geometry.md
@@ -48,6 +48,10 @@ Adobe Express provides a set of geometric shapes that you can create and style p
### Example: Add a Rectangle
+
+
+#### JavaScript
+
```js
// sandbox/code.js
import { editor } from "express-document-sdk";
@@ -65,6 +69,25 @@ const currentPage = editor.context.currentPage;
currentPage.artboards.first.children.append(rect);
```
+#### TypeScript
+
+```ts
+// sandbox/code.js
+import { editor, RectangleNode, PageNode } from "express-document-sdk";
+
+const rect: RectangleNode = editor.createRectangle();
+
+// Define rectangle dimensions.
+rect.width = 100;
+rect.height = 100;
+
+// The current page, where the rectangle will be placed
+const currentPage: PageNode = editor.context.currentPage;
+
+// Append the rectangle to the page.
+currentPage.artboards.first.children.append(rect);
+```
+
Create vs. Add to the page
@@ -75,6 +98,10 @@ You usually reference the container using [`editor.context`](../../../references
Please note that you can append multiple shapes at once with the `append()` method:
+
+
+#### JavaScript
+
```js
const s1 = editor.createRectangle();
const s2 = editor.createEllipse();
@@ -83,6 +110,16 @@ const s2 = editor.createEllipse();
editor.context.currentPage.artboards.first.children.append(s1, s2); // π
```
+#### TypeScript
+
+```ts
+const s1: RectangleNode = editor.createRectangle();
+const s2: EllipseNode = editor.createEllipse();
+// ... set all properties ...
+
+editor.context.currentPage.artboards.first.children.append(s1, s2); // π
+```
+
### Example: Add an Ellipse
Ellipses don't have a `width` and `height` properties, but a [`rx`](../../../references/document-sandbox/document-apis/classes/EllipseNode.md#rx) and [`ry`](../../../references/document-sandbox/document-apis/classes/EllipseNode.md#ry) (radius x, radius y) instead.
@@ -91,6 +128,10 @@ Ellipses don't have a `width` and `height` properties, but a [`rx`](../../../ref
An ellipse with a radius of 200 on the x-axis and 100 on the y-axis will result in a shape with 400 wide (`rx` times two) and a 200 tall (`ry` times two)!
+
+
+#### JavaScript
+
```js
// sandbox/code.js
import { editor } from "express-document-sdk";
@@ -106,13 +147,37 @@ console.log(ellipse.boundsLocal);
const currentPage = editor.context.currentPage;
// Append the rectangle to the page.
-currentPage.artboards.first.children.append(rect);
+currentPage.artboards.first.children.append(ellipse);
+```
+
+#### TypeScript
+
+```ts
+// sandbox/code.js
+import { editor, EllipseNode, PageNode } from "express-document-sdk";
+
+const ellipse: EllipseNode = editor.createEllipse();
+ellipse.rx = 200; // radius x π
+ellipse.ry = 100; // radius y π
+
+console.log(ellipse.boundsLocal);
+// { x: 0, y: 0, width: 400, height: 200 } π mind the actual bounds!
+
+// The current page, where the rectangle will be placed
+const currentPage: PageNode = editor.context.currentPage;
+
+// Append the ellipse to the page.
+currentPage.artboards.first.children.append(ellipse);
```
### Example: Style Shapes
Shapes have `fill` and `stroke` properties that you can use to style them. The following example demonstrates how to create a rectangle with a fill and a stroke.
+
+
+#### JavaScript
+
```js
// sandbox/code.js
import { editor, colorUtils, constants } from "express-document-sdk";
@@ -140,6 +205,36 @@ ellipse.stroke = stroke;
editor.context.insertionParent.children.append(ellipse);
```
+#### TypeScript
+
+```ts
+// sandbox/code.js
+import { editor, colorUtils, constants, EllipseNode, Stroke, ContainerNode } from "express-document-sdk";
+
+// Create the shape
+const ellipse: EllipseNode = editor.createEllipse();
+ellipse.rx = 200;
+ellipse.ry = 100;
+
+// π Apply the fill color
+ellipse.fill = editor.makeColorFill(colorUtils.fromHex("#F3D988"));
+
+// π Create the stroke
+const stroke: Stroke = editor.makeStroke({
+ color: colorUtils.fromHex("#E29E4E"),
+ width: 20,
+ position: constants.StrokePosition.inside,
+ dashPattern: [50, 2],
+});
+
+// π Apply the stroke
+ellipse.stroke = stroke;
+
+// Add the shape to the document
+const insertionParent: ContainerNode = editor.context.insertionParent;
+insertionParent.children.append(ellipse);
+```
+

diff --git a/src/pages/guides/learn/how_to/use_text.md b/src/pages/guides/learn/how_to/use_text.md
index 83985ea26..5a14fa3e0 100644
--- a/src/pages/guides/learn/how_to/use_text.md
+++ b/src/pages/guides/learn/how_to/use_text.md
@@ -78,6 +78,10 @@ The `editor.createText()` method accepts a string as a parameter, and returns a
### Example
+
+
+#### JavaScript
+
```js
// sandbox/code.js
import { editor } from "express-document-sdk";
@@ -99,6 +103,29 @@ insertionParent.children.append(textNode);
console.log("Text: ", textNode.fullContent.text);
```
+#### TypeScript
+
+```ts
+// sandbox/code.js
+import { editor, StandaloneTextNode, ContainerNode } from "express-document-sdk";
+
+// Create a new TextNode
+const textNode: StandaloneTextNode = editor.createText("Hello,\nWorld!");
+
+// Center the text on the page
+const insertionParent: ContainerNode = editor.context.insertionParent;
+textNode.setPositionInParent(
+ { x: insertionParent.width / 2, y: insertionParent.height / 2 },
+ { x: 0, y: 0 }
+);
+
+// Add the TextNode to the document
+insertionParent.children.append(textNode);
+
+// Get the text content
+console.log("Text: ", textNode.fullContent.text);
+```
+
The text is created with the default styles (Source Sans 3, 100pt, black). Use `\n` or `\r` to add a line break.
@@ -118,6 +145,10 @@ The text content of a `TextNode` can be replaced by setting the [`fullContent.te
### Example
+
+
+#### JavaScript
+
```js
// sandbox/code.js
import { editor } from "express-document-sdk";
@@ -127,6 +158,17 @@ const selectedTextNode = editor.context.selection[0];
selectedTextNode.fullContent.text = "Something else";
```
+#### TypeScript
+
+```ts
+// sandbox/code.js
+import { editor, TextNode } from "express-document-sdk";
+
+// Assuming the user has selected a text frame
+const selectedTextNode = editor.context.selection[0] as TextNode;
+selectedTextNode.fullContent.text = "Something else";
+```
+
## Apply Character Styles
Text styles can be applied to a `TextNode` using the [`fullContent.applyCharacterStyles()`](../../../references/document-sandbox/document-apis/classes/TextContentModel.md#applycharacterstyles) method, which applies one or more styles to the characters in the given range, leaving any style properties that were not specified unchanged.
@@ -154,6 +196,10 @@ Please note that `applyCharacterStyles()` is only one way to set styles; you can
Let's change the styles for the first three characters of a TextNode.
+
+
+#### JavaScript
+
```js
// sandbox/code.js
import { editor, constants } from "express-document-sdk";
@@ -177,12 +223,43 @@ textNode.fullContent.applyCharacterStyles(
);
```
+#### TypeScript
+
+```ts
+// sandbox/code.js
+import { editor, constants, TextNode, CharacterStyles } from "express-document-sdk";
+
+// Assuming the user has selected a text frame
+const textNode = editor.context.selection[0] as TextNode;
+
+// Apply character styles to the first three letters
+const styles: CharacterStyles = {
+ color: { red: 0, green: 0.4, blue: 0.8, alpha: 1 },
+ fontSize: 240,
+ letterSpacing: 10,
+ underline: true,
+ // baselineShift: constants.TextScriptStyle.superscript,
+};
+
+textNode.fullContent.applyCharacterStyles(
+ styles,
+ {
+ start: 0,
+ length: 3,
+ }
+);
+```
+
The `applyCharacterStyles()` method is not the only one that allows you to set styles; you can also use the `characterStyleRanges` property, which supports both getting and setting styles.
### Example: Get all Styles
To get the complete list of text character styles, you can use the [`fullContent.characterStyleRanges`](../../../references/document-sandbox/document-apis/classes/TextContentModel.md#characterstyleranges) property, which returns an array of [`CharacterStylesRange`](../../../references/document-sandbox/document-apis/interfaces/CharacterStylesRange.md) elements.
+
+
+#### JavaScript
+
```js
// sandbox/code.js
import { editor } from "express-document-sdk";
@@ -201,6 +278,26 @@ existingStyles[0].fontSize = 10;
contentModel.characterStyleRanges = existingStyles;
```
+#### TypeScript
+
+```ts
+// sandbox/code.js
+import { editor, TextNode, TextContentModel, CharacterStylesRange } from "express-document-sdk";
+
+// Assuming the user has selected a text frame
+const textNode = editor.context.selection[0] as TextNode;
+const contentModel: TextContentModel = textNode.fullContent;
+
+// Get the array of character styles
+const existingStyles: CharacterStylesRange[] = contentModel.characterStyleRanges;
+
+// Edit some properties
+existingStyles[0].fontSize = 10;
+
+// Reassign the array to apply the style changes
+contentModel.characterStyleRanges = existingStyles;
+```
+
### Example: Set all Styles
You can also use the [`characterStyleRanges`](../../../references/document-sandbox/document-apis/classes/TextContentModel.md#characterstyleranges) property to set individual ranges or them all. It's always best to get the array, modify it, and then reassign it.
diff --git a/src/pages/guides/learn/platform_concepts/communication-api.md b/src/pages/guides/learn/platform_concepts/communication-api.md
new file mode 100644
index 000000000..fd6d935b6
--- /dev/null
+++ b/src/pages/guides/learn/platform_concepts/communication-api.md
@@ -0,0 +1,193 @@
+# **Communication API Layer Overview**
+
+The Communication API layer enables **bidirectional communication** between the Document Sandbox and UI runtime environments. Here's a comprehensive breakdown:
+
+### **Core Communication APIs**
+
+#### **Required Import**
+```typescript
+import addOnSandboxSdk, { RuntimeType } from "add-on-sdk-document-sandbox";
+const { runtime } = addOnSandboxSdk.instance;
+```
+
+### **1. `runtime.exposeApi(apiObject)` - Expose Document Functions to UI**
+
+**Purpose:** Makes Document Sandbox functions callable from the UI runtime
+
+**Requirements:**
+- **Called once** per add-on lifecycle
+- **No special flags needed**
+- **Synchronous operation**
+
+**Usage Pattern:**
+```typescript
+// Document Sandbox (code.js) - Expose APIs TO the UI
+const documentApis = {
+ createRectangle: () => {
+ const rect = editor.createRectangle();
+ rect.width = 100;
+ rect.height = 100;
+ return "Rectangle created!";
+ },
+
+ processImageData: (imageBlob) => {
+ // Process image in document context
+ return editor.addImageFromBlob(imageBlob);
+ },
+
+ getDocumentInfo: () => {
+ return {
+ pageCount: editor.context.document.pages.length,
+ selectedItems: editor.context.selection.length
+ };
+ }
+};
+
+// Expose the APIs (called once)
+runtime.exposeApi(documentApis);
+```
+
+**Key Features:**
+- **Object methods** become remotely callable
+- **Class instances** can be exposed
+- **Return values** are automatically serialized
+- **Async methods** work transparently
+- **Only one API object** per runtime (calling again is no-op)
+
+### **2. `runtime.apiProxy(RuntimeType.panel)` - Access UI Functions from Document**
+
+**Purpose:** Gets access to functions exposed by the UI runtime
+
+**Requirements:**
+- **Async operation** - requires `await`
+- **Returns Promise-based proxy**
+- **Must wait for UI runtime initialization**
+
+**Usage Pattern:**
+```typescript
+// Document Sandbox (code.js) - Access APIs FROM the UI
+async function useUIApis() {
+ // Get UI API proxy (returns a Promise)
+ const uiApi = await runtime.apiProxy(RuntimeType.panel);
+
+ // Call UI functions
+ await uiApi.showNotification("Document updated!");
+ await uiApi.updateProgress(75);
+
+ const userChoice = await uiApi.showConfirmDialog({
+ title: "Confirm Action",
+ message: "Apply changes to all pages?"
+ });
+
+ if (userChoice) {
+ // Proceed with operation
+ }
+}
+```
+
+### **Runtime Types**
+
+```typescript
+export enum RuntimeType {
+ panel = "panel", // β
UI iframe runtime
+ documentSandbox = "documentSandbox", // β Cannot proxy to self
+ script = "script" // β Deprecated
+}
+```
+
+**Restrictions:**
+- **Cannot proxy to self**: `runtime.apiProxy(RuntimeType.documentSandbox)` throws error
+- **Only `panel` is supported** for `apiProxy` calls from Document Sandbox
+
+### **Communication Flow Examples**
+
+#### **Example 1: UI Triggers Document Action**
+```typescript
+// UI Runtime (index.ts)
+await documentApi.createRectangle(); // Calls function in Document Sandbox
+
+// Document Sandbox (code.ts)
+function createRectangle() {
+ const rect = editor.createRectangle();
+ // Document manipulation happens here
+ return "Success";
+}
+```
+
+#### **Example 2: Document Notifies UI of Changes**
+```typescript
+// Document Sandbox (code.ts)
+async function onSelectionChange() {
+ const uiApi = await runtime.apiProxy(RuntimeType.panel);
+ await uiApi.updateSelectionInfo({
+ count: editor.context.selection.length,
+ types: editor.context.selection.map(node => node.type)
+ });
+}
+
+// UI Runtime (index.ts)
+function updateSelectionInfo(selectionData) {
+ // Update UI display
+ document.querySelector('#selection-count').textContent = selectionData.count;
+}
+```
+
+### **Advanced Features**
+
+#### **Supported Data Types**
+- **Primitives**: `string`, `number`, `boolean`, `null`, `undefined`
+- **Objects**: Plain objects with serializable properties
+- **Arrays**: Including nested arrays
+- **Promises**: Async functions work transparently
+- **Blobs**: Binary data transfer
+
+#### **Error Handling**
+```typescript
+try {
+ const uiApi = await runtime.apiProxy(RuntimeType.panel);
+ await uiApi.riskyOperation();
+} catch (error) {
+ console.error("UI operation failed:", error);
+ // Error is automatically propagated across runtime boundary
+}
+```
+
+#### **Class Instance Exposure**
+```typescript
+class DocumentController {
+ createShape(type) { /* ... */ }
+ deleteShape(id) { /* ... */ }
+ getShapeInfo(id) { /* ... */ }
+}
+
+const controller = new DocumentController();
+runtime.exposeApi(controller); // Entire class instance is exposed
+```
+
+### **Security & Performance Notes**
+
+1. **Automatic Serialization**: Data is automatically serialized/deserialized across runtime boundaries
+2. **Type Validation**: Built-in validation prevents unsafe data transfer
+3. **Promise-Based**: All cross-runtime calls are asynchronous for performance
+4. **Single API Object**: Only one API object can be exposed per runtime (prevents conflicts)
+5. **Error Propagation**: Errors are automatically marshaled across runtime boundaries
+
+### **Typical Communication Pattern**
+
+```typescript
+// Document Sandbox Setup
+const documentApis = {
+ // Functions UI can call
+ performDocumentOperation: async (params) => { /* ... */ }
+};
+runtime.exposeApi(documentApis);
+
+// Get UI API access
+const uiApi = await runtime.apiProxy(RuntimeType.panel);
+
+// Document can now:
+// 1. Receive calls from UI via exposed APIs
+// 2. Make calls to UI via proxy APIs
+```
+
+This creates a **bidirectional communication channel** where both runtimes can call each other's functions seamlessly.
diff --git a/src/pages/guides/learn/platform_concepts/constants-guide.md b/src/pages/guides/learn/platform_concepts/constants-guide.md
new file mode 100644
index 000000000..8aa846646
--- /dev/null
+++ b/src/pages/guides/learn/platform_concepts/constants-guide.md
@@ -0,0 +1,245 @@
+# Add-on UI SDK Constants
+
+The Add-on UI SDK constants provide type-safe ways to interact with all the major Add-on UI SDK features developers commonly use. This includes:
+
+- Constants available in `addOnUISdk.constants.*`
+- Constants available only as named exports (specific import required)
+
+See the [Import Patterns](#import-patterns) section for details on how to access each type.
+
+
+
+The constants listed in this reference are equal to their variable name as a string value, ie: for the `ButtonType` constant, `primary` has a value of "primary".
+
+## **Dialog & UI Interaction Constants**
+
+| Constant | Values | Description | Usage |
+|----------|--------|-------------|-------|
+| **`Variant`** | `confirmation`, `information`, `warning`, `destructive`, `error`, `input`, `custom` | Dialog types for `showModalDialog()` | `addOnUISdk.app.showModalDialog({variant: Variant.error})` |
+| **`ButtonType`** | `primary`, `secondary`, `cancel`, `close` | Button types in dialog responses | Check `result.buttonType === ButtonType.primary` |
+| **`FieldType`** | `text` | Input field types for input dialogs | Used in dialog field configuration |
+| **`DialogResultType`** | `alert`, `input`, `custom` | Types of dialog results returned | Determine result structure type |
+
+## **Platform & Environment Constants**
+
+| Constant | Values | Description | Usage |
+|----------|--------|-------------|-------|
+| **`PlatformType`** | `iOS`, `iPadOS`, `chromeOS`, `android`, `chromeBrowser`, `firefoxBrowser`, `edgeBrowser`, `samsungBrowser`, `safariBrowser`, `unknown` | Platform identification | `platform.platformType === PlatformType.iOS` |
+| **`PlatformEnvironment`** | `app`, `web` | Runtime environment type | Check if running in app vs web |
+| **`DeviceClass`** | `mobile`, `tablet`, `desktop` | Device category | Responsive design decisions |
+| **`RuntimeType`** | `panel`, `dialog`, `documentSandbox`, `command` | Add-on runtime types | Communication API configuration |
+
+## **Document Export & Rendering Constants**
+
+| Constant | Values | Description | Usage |
+|----------|--------|-------------|-------|
+| **`Range`** | `currentPage`, `entireDocument`, `specificPages` | Rendition page ranges | `createRenditions({range: Range.currentPage})` |
+| **`RenditionFormat`** | `png`, `jpg`, `mp4`, `pdf`, `pptx` | Export file formats | Specify output format for renditions |
+| **`RenditionType`** | `page` | Type of rendition | Document export configuration |
+| **`RenditionIntent`** | `export`, `preview`, `print` | Purpose of rendition | Optimize rendering for use case |
+
+## **Video & Media Constants**
+
+| Constant | Values | Description | Usage |
+|----------|--------|-------------|-------|
+| **`VideoResolution`** | `sd480p`, `hd720p`, `fhd1080p`, `qhd1440p`, `uhd2160p`, `custom` | Video export resolutions | Video rendition quality settings |
+| **`FrameRate`** | `fps23_976`, `fps24`, `fps25`, `fps29_97`, `fps30`, `fps60` | Video frame rates | Video export frame rate |
+| **`BitRate`** | `mbps4` through `mbps50` | Video bit rates in bps | Video compression settings |
+| **`BleedUnit`** | `Inch`, `Millimeter` | Print bleed units | Print preparation |
+
+## **Editor Panel Navigation Constants**
+
+| Constant | Values | Description | Usage |
+|----------|--------|-------------|-------|
+| **`EditorPanel`** | `search`, `yourStuff`, `templates`, `media`, `text`, `elements`, `grids`, `brands`, `addOns` | Express editor panels | `openEditorPanel(EditorPanel.media)` |
+| **`MediaTabs`** | `video`, `audio`, `photos` | Media panel tabs | Navigate to specific media type |
+| **`ElementsTabs`** | `designAssets`, `backgrounds`, `shapes`, `stockIcons`, `charts` | Elements panel tabs | Navigate to specific element type |
+| **`PanelActionType`** | `search`, `navigate` | Panel action types | Panel interaction configuration |
+
+## **Color Picker Constants**
+
+| Constant | Values | Description | Usage |
+|----------|--------|-------------|-------|
+| **`ColorPickerPlacement`** | `top`, `bottom`, `left`, `right` | Color picker positioning | `showColorPicker(element, {placement: ColorPickerPlacement.top})` |
+
+## **File Management Constants**
+
+| Constant | Values | Description | Usage |
+|----------|--------|-------------|-------|
+| **`FileSizeLimitUnit`** | `KB`, `MB` | File size limit units | File upload constraints |
+
+## **OAuth & Authentication Constants**
+
+| Constant | Values | Description | Usage |
+|----------|--------|-------------|-------|
+| **`AuthorizationStatus`** | (imported from @hz/wxp-oauth) | OAuth authorization states | Check authorization status |
+
+## **Usage Examples**
+
+```typescript
+import addOnUISdk, {
+ Variant,
+ PlatformType,
+ RenditionFormat,
+ EditorPanel
+} from "https://new.express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Dialog with error variant
+await addOnUISdk.app.showModalDialog({
+ variant: Variant.error,
+ title: "Upload Failed",
+ description: "File size exceeds limit"
+});
+
+// Platform-specific behavior
+const platform = await addOnUISdk.app.getCurrentPlatform();
+if (platform.platformType === PlatformType.iOS) {
+ // iOS-specific handling
+}
+
+// Export document as PNG
+await addOnUISdk.app.document.createRenditions({
+ format: RenditionFormat.png,
+ range: Range.currentPage
+});
+
+// Navigate to media panel
+addOnUISdk.app.ui.openEditorPanel(EditorPanel.media);
+```
+
+## Notes for Developers
+
+- **Some constants are available as named exports** from the Add-on UI SDK
+- **Use constants instead of string literals** for type safety and future compatibility
+
+### Import Patterns
+
+Adobe Express Add-on SDK constants are available through different import patterns depending on the constant type. Understanding these patterns is essential for avoiding runtime errors.
+
+#### Named Exports (Import Required)
+
+These constants are **only available as named exports** and must be imported explicitly. They are **NOT** available through `addOnUISdk.constants.*`:
+
+```javascript
+import addOnUISdk, {
+ AppEvent,
+ ColorPickerEvent,
+ SupportedMimeTypes,
+ EntrypointType,
+ PdfReturnUrlType
+} from "https://new.express.adobe.com/static/add-on-sdk/sdk.js";
+
+// β
Correct usage
+const docxMimeType = SupportedMimeTypes.docx;
+const colorChangeEvent = ColorPickerEvent.colorChange;
+
+// β Will NOT work - these are not in the constants object
+const docxMimeType = addOnUISdk.constants.SupportedMimeTypes.docx; // undefined
+```
+
+#### Dual Access Constants
+
+These constants support **both import patterns** for flexibility. You can use either approach:
+
+```javascript
+import addOnUISdk, { Range, RenditionFormat, Variant } from "https://new.express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Option 1: Named import (recommended for cleaner code)
+const currentPage = Range.currentPage;
+const pngFormat = RenditionFormat.png;
+const confirmDialog = Variant.confirmation;
+
+// Option 2: Constants object access (traditional pattern)
+const currentPage = addOnUISdk.constants.Range.currentPage;
+const pngFormat = addOnUISdk.constants.RenditionFormat.png;
+const confirmDialog = addOnUISdk.constants.Variant.confirmation;
+```
+
+**Dual Access Constants List:**
+
+- `Range` / `addOnUISdk.constants.Range`
+- `RenditionFormat` / `addOnUISdk.constants.RenditionFormat`
+- `RenditionType` / `addOnUISdk.constants.RenditionType`
+- `RenditionIntent` / `addOnUISdk.constants.RenditionIntent`
+- `Variant` / `addOnUISdk.constants.Variant`
+- `DialogResultType` / `addOnUISdk.constants.DialogResultType`
+- `ButtonType` / `addOnUISdk.constants.ButtonType`
+- `RuntimeType` / `addOnUISdk.constants.RuntimeType`
+- `BleedUnit` / `addOnUISdk.constants.BleedUnit`
+- `EditorPanel` / `addOnUISdk.constants.EditorPanel`
+- `MediaTabs` / `addOnUISdk.constants.MediaTabs`
+- `ElementsTabs` / `addOnUISdk.constants.ElementsTabs`
+- `PanelActionType` / `addOnUISdk.constants.PanelActionType`
+- `ColorPickerPlacement` / `addOnUISdk.constants.ColorPickerPlacement`
+- `AuthorizationStatus` / `addOnUISdk.constants.AuthorizationStatus`
+- `FieldType` / `addOnUISdk.constants.FieldType`
+- `PlatformEnvironment` / `addOnUISdk.constants.PlatformEnvironment`
+- `DeviceClass` / `addOnUISdk.constants.DeviceClass`
+- `PlatformType` / `addOnUISdk.constants.PlatformType`
+- `MediaType` / `addOnUISdk.constants.MediaType`
+- `VideoResolution` / `addOnUISdk.constants.VideoResolution`
+- `FrameRate` / `addOnUISdk.constants.FrameRate`
+- `BitRate` / `addOnUISdk.constants.BitRate`
+- `FileSizeLimitUnit` / `addOnUISdk.constants.FileSizeLimitUnit`
+- `LinkOptions` / `addOnUISdk.constants.LinkOptions`
+
+### Best Practices
+
+1. **Use named imports for cleaner code** when you know which constants you need:
+ ```javascript
+ import addOnUISdk, { Range, RenditionFormat } from "https://new.express.adobe.com/static/add-on-sdk/sdk.js";
+
+ const options = {
+ range: Range.currentPage,
+ format: RenditionFormat.png
+ };
+ ```
+
+2. **Use constants object for dynamic access** when the constant name is determined at runtime:
+ ```javascript
+ const format = addOnUISdk.constants.RenditionFormat[userSelectedFormat];
+ ```
+
+3. **Always import named-only exports** - there's no alternative way to access them:
+ ```javascript
+ import addOnUISdk, { SupportedMimeTypes } from "https://new.express.adobe.com/static/add-on-sdk/sdk.js";
+ ```
+
+### Quick Reference Table
+
+| Constant | Named Export | Constants Object | Import Required |
+|----------|--------------|------------------|-----------------|
+| `AppEvent` | β
| β | **Yes** |
+| `ColorPickerEvent` | β
| β | **Yes** |
+| `SupportedMimeTypes` | β
| β | **Yes** |
+| `EntrypointType` | β
| β | **Yes** |
+| `PdfReturnUrlType` | β
| β | **Yes** |
+| `Range` | β
| β
| Optional |
+| `RenditionFormat` | β
| β
| Optional |
+| `Variant` | β
| β
| Optional |
+| `ButtonType` | β
| β
| Optional |
+| `FieldType` | β
| β
| Optional |
+| `PlatformEnvironment` | β
| β
| Optional |
+| `DeviceClass` | β
| β
| Optional |
+| `PlatformType` | β
| β
| Optional |
+| `AuthorizationStatus` | β
| β
| Optional |
+| `RenditionType` | β
| β
| Optional |
+| `RenditionIntent` | β
| β
| Optional |
+| `DialogResultType` | β
| β
| Optional |
+| `RuntimeType` | β
| β
| Optional |
+| `BleedUnit` | β
| β
| Optional |
+| `EditorPanel` | β
| β
| Optional |
+| `MediaTabs` | β
| β
| Optional |
+| `ElementsTabs` | β
| β
| Optional |
+| `PanelActionType` | β
| β
| Optional |
+| `ColorPickerPlacement` | β
| β
| Optional |
+| `MediaType` | β
| β
| Optional |
+| `VideoResolution` | β
| β
| Optional |
+| `FrameRate` | β
| β
| Optional |
+| `BitRate` | β
| β
| Optional |
+| `FileSizeLimitUnit` | β
| β
| Optional |
+| `LinkOptions` | β
| β
| Optional |
+
+
+
+**Important:** Attempting to access named-only exports through `addOnUISdk.constants.*` will return `undefined` and may cause runtime errors. Always check the table above or use TypeScript for compile-time validation.
diff --git a/src/pages/guides/learn/platform_concepts/doc-sandbox.md b/src/pages/guides/learn/platform_concepts/doc-sandbox.md
new file mode 100644
index 000000000..ffb5df031
--- /dev/null
+++ b/src/pages/guides/learn/platform_concepts/doc-sandbox.md
@@ -0,0 +1,79 @@
+# Document Sandbox: The Full Picture
+
+The Document Sandbox includes **three main components**:
+
+## 1. **Document APIs**
+
+- **Scenegraph manipulation**: `RectangleNode`, `TextNode`, `PageNode`, etc.
+- **Editor operations**: `editor.createRectangle()`, `editor.queueAsyncEdit()`
+- **Document structure**: Direct access to document elements and properties
+
+## 2. **Communication API Layer**
+
+- **`runtime.exposeApi()`**: Expose functions from Document Sandbox to UI iframe
+- **`runtime.apiProxy()`**: Get proxy to call functions in UI iframe
+- **Bidirectional communication**: Document Sandbox β UI iframe communication
+
+## 3. **Global Browser API Access** (Limited Subset)
+
+- **Console**: `console.log()`, `console.error()`, etc.
+- **Blob API**: `new Blob()`, `blob.arrayBuffer()`, `blob.text()`
+- **Basic JavaScript globals**: But **not** full DOM access
+
+### **Example: Full Document Sandbox Usage**
+
+```typescript
+// Document Sandbox code (runs in QuickJS/isolated environment)
+import addOnSandboxSdk from "add-on-sdk-document-sandbox";
+import { editor, constants } from "express-document-sdk";
+
+const { runtime } = addOnSandboxSdk.instance;
+
+// 1. DOCUMENT APIs - Direct scenegraph manipulation
+function createLayout() {
+ const rect = editor.createRectangle();
+ rect.width = 100;
+ rect.height = 50;
+ editor.context.insertionParent.children.append(rect);
+}
+
+// 2. COMMUNICATION APIs - Expose functions to UI iframe
+const sandboxApi = {
+ createLayout,
+ addCustomText: (text: string) => {
+ const textNode = editor.createText(text);
+ editor.context.insertionParent.children.append(textNode);
+ }
+};
+
+runtime.exposeApi(sandboxApi);
+
+// Get proxy to call UI iframe functions
+const uiProxy = await runtime.apiProxy(RuntimeType.panel);
+uiProxy.updateStatus("Layout created!");
+
+// 3. GLOBAL BROWSER APIs - Limited subset available
+console.log("Document sandbox initialized");
+const data = new Blob(["Hello"], { type: "text/plain" });
+const text = await data.text();
+```
+
+### **Architecture: Two Runtime Communication**
+
+```
+βββββββββββββββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββββββββββ
+β UI iframe β β Document Sandbox β
+β (addOnUISdk) β β (Document Sandbox SDK) β
+βββββββββββββββββββββββββββββββββββββββ€ βββββββββββββββββββββββββββββββββββββββ€
+β β’ DOM access β β β’ Document APIs (editor, nodes) β
+β β’ Full browser APIs βββββΊβ β’ Limited browser APIs (console, β
+β β’ Event handling β β Blob) β
+β β’ UI interactions β β β’ Communication APIs (runtime) β
+β β’ addOnUISdk.app.document.addImage()β β β’ Direct scenegraph manipulation β
+βββββββββββββββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββββββββββ
+ β β
+ β runtime.apiProxy() β
+ β runtime.exposeApi() β
+ ββββββββββββββββββββββββββββββββββββββββββββββββ
+ Communication Layer
+```
diff --git a/src/pages/guides/learn/platform_concepts/document-api.md b/src/pages/guides/learn/platform_concepts/document-api.md
index 49348dd3b..7104c26eb 100644
--- a/src/pages/guides/learn/platform_concepts/document-api.md
+++ b/src/pages/guides/learn/platform_concepts/document-api.md
@@ -206,6 +206,17 @@ A specific **naming convention** exists for methods used in the Adobe Express DO
- `create*`: used for live document objects, like `createEllipse()`
- `add*`: reserved to create complex structures like Pages and Artboards, adding them to the parent list automatically in a way that may also update the insertion point. Found in `addPage()` and `addArtboard()`.
+
+
+Common Mistake: Use `addPage()`, not `createPage()`
+
+**There is no `createPage()` method** in the Adobe Express Document API. This is a frequent source of confusion for developers and LLMs.
+
+β
**Correct:** `editor.addPage({ width: 1080, height: 1080 })`
+β **Wrong:** `editor.createPage()` (doesn't exist)
+
+See the [Manage Pages how-to guide](../how_to/manage_pages.md) for comprehensive examples and best practices.
+
Speaking of colors, the `ColorUtils` module can output a proper `Color` from either a partial RGB object (where the `alpha` property is optional, defaulting to `1`) or a Hex string with or without alpha, providing the reverse function as well.
```js
diff --git a/src/pages/guides/learn/platform_concepts/runtime-architecture.md b/src/pages/guides/learn/platform_concepts/runtime-architecture.md
new file mode 100644
index 000000000..c66e33f20
--- /dev/null
+++ b/src/pages/guides/learn/platform_concepts/runtime-architecture.md
@@ -0,0 +1,657 @@
+---
+keywords:
+ - Adobe Express
+ - Add-on SDK
+ - Adobe Express Editor
+ - SDK (Software Development Kit)
+ - JavaScript
+ - Extend
+ - Extensibility
+ - API
+ - Runtime
+ - Communication
+ - Document Sandbox
+ - Document Sandbox SDK
+ - Document API
+ - UI Runtime
+ - Architecture
+ - Two-Runtime System
+title: Runtime Architecture & Communication
+description: Understanding the two-runtime architecture and communication system in Adobe Express add-ons.
+contributors:
+ - https://github.com/hollyschinsky
+---
+
+# Runtime Architecture & Communication
+
+Understanding Adobe Express add-on architecture is crucial for building effective add-ons. This guide explains the two-runtime system and how communication works between environments.
+
+## Two-Runtime Architecture Overview
+
+Adobe Express add-ons run in **two separate JavaScript execution environments** that work together:
+
+1. **UI Runtime** - Your add-on's user interface (iframe)
+2. **Document Sandbox** - Secure environment for document manipulation
+
+## Architecture Diagrams
+
+### **Architecture: Two Runtime Communication**
+
+```
+βββββββββββββββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββββββββββ
+β UI iframe β β Document Sandbox β
+β (Add-on UI SDK) β β (Document Sandbox SDK) β
+βββββββββββββββββββββββββββββββββββββββ€ βββββββββββββββββββββββββββββββββββββββ€
+β β’ DOM access β β β’ Document APIs (editor, nodes) β
+β β’ Full browser APIs βββββΊβ β’ Limited browser APIs (console, β
+β β’ Event handling β β Blob) β
+β β’ UI interactions β β β’ Communication APIs (runtime) β
+β β’ addOnUISdk.app.document.addImage()β β β’ Direct scenegraph manipulation β
+βββββββββββββββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββββββββββ
+ β β
+ β runtime.apiProxy() β
+ β runtime.exposeApi() β
+ ββββββββββββββββββββββββββββββββββββββββββββββββ
+ Communication Layer
+```
+## What is the Runtime Object?
+
+The `runtime` object acts as a **communication bridge** between the two environments. Each environment has its own runtime object:
+
+- **UI Runtime**: `addOnUISdk.instance.runtime`
+- **Document Sandbox**: `addOnSandboxSdk.instance.runtime`
+
+The communication bridge can be thought of like a phone line - each side has their own phone to call the other side.
+
+## The Two Environments Explained
+
+### UI Runtime Environment
+
+**File:** `index.js` or `index.html`
+**Purpose:** User interface and browser interactions
+**SDK Import:**
+```js
+import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
+```
+
+**Capabilities:**
+
+- Render your add-on's user interface
+- Handle user interactions (clicks, form inputs)
+- Access browser APIs (fetch, localStorage)
+- OAuth authentication
+- Modal dialogs
+- File uploads/downloads
+
+### Document Sandbox Environment
+
+**File:** `code.js`
+**Purpose:** Document manipulation and content creation
+**SDK Import:**
+```js
+import addOnSandboxSdk from "add-on-sdk-document-sandbox";
+```
+
+**Capabilities:**
+
+- Access Adobe Express Document API
+- Create and modify document elements
+- Export renditions
+- Secure, isolated execution
+- Limited browser API access
+
+## Communication Flow
+
+### From UI to Document Sandbox
+
+When you want to manipulate the document from your UI:
+
+#### UI Runtime (index.js)
+
+```js
+// ui/index.js - Your add-on's interface
+import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
+
+addOnUISdk.ready.then(async () => {
+ const { runtime } = addOnUISdk.instance;
+
+ // Button click handler
+ document.getElementById("createText").addEventListener("click", async () => {
+ // Get a proxy to call document sandbox functions
+ const sandboxProxy = await runtime.apiProxy("documentSandbox");
+
+ // Call function exposed in code.js
+ await sandboxProxy.createTextElement("Hello World!");
+ });
+});
+```
+
+#### Document Sandbox (code.js)
+
+```js
+// sandbox/code.js - Document manipulation
+import addOnSandboxSdk from "add-on-sdk-document-sandbox";
+import { editor } from "express-document-sdk";
+
+const { runtime } = addOnSandboxSdk.instance;
+
+// Expose functions that UI can call
+runtime.exposeApi({
+ createTextElement: async function(text) {
+ await editor.queueAsyncEdit(() => {
+ const textNode = editor.createText(text);
+ editor.context.insertionParent.children.append(textNode);
+ });
+ }
+});
+```
+
+### From Document Sandbox to UI
+
+When you want to update the UI from document operations:
+
+#### Document Sandbox (code.js)
+```js
+// sandbox/code.js - Document manipulation
+import addOnSandboxSdk from "add-on-sdk-document-sandbox";
+
+const { runtime } = addOnSandboxSdk.instance;
+
+async function processDocument() {
+ // Get a proxy to call UI functions
+ const uiProxy = await runtime.apiProxy("panel");
+
+ // Update UI with progress
+ await uiProxy.updateProgress(50);
+
+ // Document manipulation here...
+
+ await uiProxy.updateProgress(100);
+}
+```
+
+#### UI Runtime (index.js)
+```js
+// ui/index.js - Your add-on's interface
+import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
+
+addOnUISdk.ready.then(() => {
+ const { runtime } = addOnUISdk.instance;
+
+ // Expose functions that document sandbox can call
+ runtime.exposeApi({
+ updateProgress: function(percentage) {
+ const progressBar = document.getElementById("progress");
+ progressBar.style.width = percentage + "%";
+ }
+ });
+});
+```
+
+### Runtime Type Detection
+
+#### UI Runtime (index.js)
+```js
+// ui/index.js - Your add-on's interface
+import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
+
+addOnUISdk.ready.then(() => {
+ const { runtime } = addOnUISdk.instance;
+ // Check what type of runtime you're in
+ console.log(runtime.type); // "panel"
+});
+```
+
+#### Document Sandbox (code.js)
+
+```js
+import addOnSandboxSdk from "add-on-sdk-document-sandbox";
+
+const { runtime } = addOnSandboxSdk.instance;
+
+// Check what type of runtime you're in
+console.log(runtime.type); // "documentSandbox"
+```
+
+## Understanding the Document Sandbox SDK Imports
+
+### When do I need both SDK imports in `code.js`?
+
+This is a common source of confusion. In your `code.js` file, you may need one or both imports depending on what your add-on does:
+
+#### Option 1: Communication Only
+```js
+// sandbox/code.js - Only communication, no document manipulation
+import addOnSandboxSdk from "add-on-sdk-document-sandbox";
+
+const { runtime } = addOnSandboxSdk.instance;
+
+// Only exposing APIs, not creating document content
+runtime.exposeApi({
+ processData: function(data) {
+ // Process data, return results
+ return data.map(item => item.toUpperCase());
+ }
+});
+```
+
+#### Option 2: Document Manipulation Only
+```js
+// sandbox/code.js - Only document creation, no communication
+import { editor } from "express-document-sdk";
+
+// Directly manipulate document without UI communication
+editor.queueAsyncEdit(() => {
+ const text = editor.createText("Auto-generated content");
+ editor.context.insertionParent.children.append(text);
+});
+```
+
+#### Option 3: Both Communication AND Document Manipulation
+```js
+// sandbox/code.js - Most common pattern
+import addOnSandboxSdk from "add-on-sdk-document-sandbox"; // For communication
+import { editor } from "express-document-sdk"; // For document manipulation
+
+const { runtime } = addOnSandboxSdk.instance;
+
+// Expose APIs that manipulate the document
+runtime.exposeApi({
+ createTextElement: async function(text) {
+ await editor.queueAsyncEdit(() => {
+ const textNode = editor.createText(text);
+ editor.context.insertionParent.children.append(textNode);
+ });
+ }
+});
+```
+
+### Quick Decision Guide
+
+**Do I need `addOnSandboxSdk`?**
+
+- β
YES if your `code.js` needs to communicate with the UI
+- β
YES if UI triggers document operations
+- β NO if `code.js` runs independently
+
+**Do I need `express-document-sdk`?**
+
+- β
YES if creating/modifying document content
+- β
YES if accessing document properties
+- β NO if only processing data or communicating
+
+### Examples
+
+#### Example 1: Text Generator Add-on
+
+```js
+// sandbox/code.js - Needs BOTH imports
+import addOnSandboxSdk from "add-on-sdk-document-sandbox"; // UI sends text data
+import { editor } from "express-document-sdk"; // Create text elements
+
+const { runtime } = addOnSandboxSdk.instance;
+
+runtime.exposeApi({
+ generateText: async function(userInput) {
+ await editor.queueAsyncEdit(() => {
+ const text = editor.createText(userInput);
+ editor.context.insertionParent.children.append(text);
+ });
+ }
+});
+```
+
+#### Example 2: Document Analytics Add-on
+
+```js
+// sandbox/code.js - Needs BOTH imports
+import addOnSandboxSdk from "add-on-sdk-document-sandbox"; // Send results to UI
+import { editor } from "express-document-sdk"; // Analyze document
+
+const { runtime } = addOnSandboxSdk.instance;
+
+runtime.exposeApi({
+ analyzeDocument: function() {
+ const pageCount = editor.context.insertionParent.children.length;
+ return { pageCount, elements: pageCount * 5 }; // Send data back to UI
+ }
+});
+```
+
+#### Example 3: Document Analysis Utility
+
+```js
+// sandbox/code.js - Only needs express-document-sdk
+import { editor } from "express-document-sdk";
+
+// Analyze current document structure (no UI communication needed)
+function analyzeDocument() {
+ const pages = editor.context.insertionParent.children;
+ const elementCount = pages.length;
+
+ console.log(`Document analysis: ${elementCount} elements found`);
+
+ // Could save analysis results to document metadata or
+ // trigger other document operations based on analysis
+ return { elementCount, timestamp: new Date().toISOString() };
+}
+
+// Execute analysis
+const results = analyzeDocument();
+```
+
+## Common Patterns
+
+### Pattern 1: UI-Triggered Document Operations (Most Common)
+
+User interactions in the UI trigger document changes:
+
+```js
+// UI: User clicks button β Document: Create content
+// Requires BOTH imports in code.js
+```
+
+### Pattern 2: Document-Driven UI Updates
+
+Document analysis sends results to update the UI:
+
+```js
+// Document: Analyze content β UI: Show results
+// Requires BOTH imports in code.js
+```
+
+### Pattern 3: Independent Document Operations
+
+Document analysis or operations that run without UI interaction:
+
+```js
+// Document: Analyze/process content
+// Only requires express-document-sdk
+```
+
+## Complete add-on-sdk-document-sandbox Package Overview
+
+The `add-on-sdk-document-sandbox` package provides more than just the `runtime` object. Here's what you get:
+
+### Core Features
+
+#### 1. Communication System (`addOnSandboxSdk.instance.runtime`)
+```js
+import addOnSandboxSdk from "add-on-sdk-document-sandbox";
+
+const { runtime } = addOnSandboxSdk.instance;
+
+// Expose APIs to UI
+runtime.exposeApi({ /* your functions */ });
+
+// Get proxy to UI APIs
+const uiProxy = await runtime.apiProxy("panel");
+```
+
+#### 2. Injected Web APIs (Global - No Import Needed)
+The document sandbox automatically injects limited browser APIs for common tasks. See the complete [Web APIs Reference](../../../references/document-sandbox/web/index.md) for details.
+
+```js
+// These are automatically available in your code.js
+console.log("Debugging output");
+console.error("Something went wrong");
+console.warn("Be careful here");
+console.clear(); // Clear console
+```
+
+#### 3. Secure Execution Environment
+- **Isolated JavaScript context**: Your code runs in a secure sandbox
+- **Limited browser APIs**: Only essential APIs are available
+- **Performance considerations**: Slower than UI runtime but secure
+- **No direct DOM access**: Must communicate through UI runtime
+
+### What You DON'T Need to Import
+
+These are automatically injected and available globally in the document sandbox. For complete details, see [Web APIs Reference](../../../references/document-sandbox/web/index.md).
+
+```js
+// β
Available automatically - no import needed
+console.log("This works!");
+console.error("Error logging works!");
+console.warn("Warning logging works!");
+console.info("Info logging works!");
+console.debug("Debug logging works!");
+console.clear(); // Clear console
+console.assert(condition, "Assertion message");
+
+// Blob interface for binary data
+const blob = new Blob(['data'], { type: 'text/plain' });
+blob.text().then(text => console.log(text));
+```
+
+### What You DO Need to Import
+
+#### For Communication:
+```js
+import addOnSandboxSdk from "add-on-sdk-document-sandbox";
+const { runtime } = addOnSandboxSdk.instance;
+```
+
+#### For Document Manipulation:
+```js
+import { editor, colorUtils, constants, fonts } from "express-document-sdk";
+```
+
+### Debugging Capabilities
+
+Since the document sandbox has limited debugging, use these patterns:
+
+```js
+// Basic debugging with console
+console.log("Variable value:", myVariable);
+
+// Object inspection
+console.log("Full object:", JSON.stringify(myObject, null, 2));
+
+// Error tracking
+try {
+ // Risky operation
+ const result = editor.createText("Hello");
+ console.log("Success:", result);
+} catch (error) {
+ console.error("Operation failed:", error.message);
+}
+
+// Assertion testing
+console.assert(myVariable !== undefined, "Variable should be defined");
+```
+
+### Quick Reference: All SDK Imports
+
+| Feature | UI Runtime
`addOnUISdk` | Document Sandbox
`addOnSandboxSdk` | Document Sandbox
`express-document-sdk` |
+|---------|------------|------------------|-----------------|
+| **Import Statement** | `import addOnUISdk from "https://new.express.adobe.com/static/add-on-sdk/sdk.js"` | `import addOnSandboxSdk from "add-on-sdk-document-sandbox"` | `import { editor } from "express-document-sdk"` |
+| **File Location** | `index.js/index.html` | `code.js` | `code.js` |
+| **Primary Purpose** | User interface & browser interactions | Communication between environments | Document manipulation |
+| **Runtime Communication** | β
`instance.runtime` | β
`instance.runtime` | β No communication |
+| **Document Creation** | β No direct access | β No direct access | β
`editor.createText()`, etc. |
+| **Document Reading** | β No direct access | β No direct access | β
`editor.context` |
+| **Export Renditions** | β
`app.document.createRenditions()` | β No direct access | β No direct access |
+| **Modal Dialogs** | β
`app.showModalDialog()` | β No direct access | β No direct access |
+| **OAuth** | β
`app.oauth` | β No direct access | β No direct access |
+| **File Upload/Download** | β
Full browser APIs | β No direct access | β No direct access |
+| **DOM Manipulation** | β
Full DOM access | β No DOM access | β No DOM access |
+| **Browser APIs** | β
All browser APIs | β Limited (console, Blob) | β Limited (console, Blob) |
+| **Platform Detection** | β
`app.getCurrentPlatform()` | β No direct access | β No direct access |
+| **Client Storage** | β
`instance.clientStorage` | β No direct access | β No direct access |
+| **Constants** | β
`constants.*` | β No constants | β
Document constants |
+
+### Manifest Configuration
+
+The sandbox requires proper manifest setup:
+
+```json
+{
+ "entryPoints": [
+ {
+ "type": "panel",
+ "id": "panel1",
+ "main": "index.html",
+ "documentSandbox": "code.js"
+ }
+ ]
+}
+```
+
+### SDK Import Decision Matrix
+
+| Your Add-on Needs | UI Runtime | Document Sandbox | Required Imports |
+|-------------------|------------|------------------|------------------|
+| **UI only** (no document changes) | β
| β | `addOnUISdk` |
+| **Document manipulation only** | β | β
| `express-document-sdk` |
+| **UI + Document communication** | β
| β
| `addOnUISdk` + `addOnSandboxSdk` |
+| **UI + Document creation** | β
| β
| `addOnUISdk` + `addOnSandboxSdk` + `express-document-sdk` |
+| **Data processing only** | β | β
| `addOnSandboxSdk` (for communication) |
+| **Export/Import only** | β
| β | `addOnUISdk` |
+
+### Common Import Patterns
+
+```js
+// Pattern 1: UI-only add-on (no document changes)
+// index.js
+import addOnUISdk from "https://new.express.adobe.com/static/add-on-sdk/sdk.js";
+// No code.js file needed
+
+// Pattern 2: Document manipulation only
+// code.js
+import { editor } from "express-document-sdk";
+// No index.js communication needed
+
+// Pattern 3: Full communication + document manipulation (most common)
+// index.js
+import addOnUISdk from "https://new.express.adobe.com/static/add-on-sdk/sdk.js";
+
+// code.js
+import addOnSandboxSdk from "add-on-sdk-document-sandbox"; // For communication
+import { editor } from "express-document-sdk"; // For document APIs
+```
+
+## Best Practices
+
+1. **Clear File Organization**
+ - Keep UI logic in `index.js`
+ - Keep document logic in `code.js`
+ - Use consistent naming for exposed APIs
+
+2. **Error Handling**
+ - Always wrap API calls in try-catch blocks
+ - Provide meaningful error messages to users
+ - Handle communication failures gracefully
+ - Use `console.error()` for debugging in sandbox
+
+3. **Performance**
+ - Minimize data transfer between environments
+ - Batch multiple operations when possible
+ - Use appropriate data types (see [Communication APIs](../../../references/document-sandbox/communication/index.md#data-types))
+ - Remember sandbox runs slower than UI runtime
+
+4. **Debugging**
+ - Use `console.log` in both environments
+ - Check browser dev tools for UI runtime
+ - Use sandbox console for document sandbox debugging
+ - Use `console.assert()` for validation checks
+
+## Error Handling
+
+### Common Error: "Runtime is undefined"
+
+β **Wrong:** Trying to use runtime before SDK is ready
+```js
+const { runtime } = addOnUISdk.instance; // Error! SDK not ready yet
+```
+
+β
**Correct:** Wait for SDK ready state
+```js
+addOnUISdk.ready.then(() => {
+ const { runtime } = addOnUISdk.instance; // Now it's safe
+});
+```
+
+### Common Error: "Cannot read property 'apiProxy' of undefined"
+
+β **Wrong:** Using wrong SDK in wrong environment
+```js
+// In code.js (Document Sandbox)
+import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
+const { runtime } = addOnUISdk.instance; // Wrong SDK!
+```
+
+β
**Correct:** Use appropriate SDK for each environment
+```js
+// In code.js (Document Sandbox)
+import addOnSandboxSdk from "add-on-sdk-document-sandbox";
+const { runtime } = addOnSandboxSdk.instance; // Correct SDK!
+```
+
+## Frequently Asked Questions
+
+### Q: Why are there two different runtime objects?
+
+**A:** Each environment has its own runtime object that acts as a "communication phone." The UI runtime calls the document sandbox, and the document sandbox runtime calls the UI. This separation ensures security and proper isolation.
+
+### Q: When do I use `addOnUISdk.instance.runtime` vs `addOnSandboxSdk.instance.runtime`?
+
+**A:** Use the runtime object from the environment you're currently in:
+- In `index.js` (UI): Use `addOnUISdk.instance.runtime`
+- In `code.js` (Sandbox): Use `addOnSandboxSdk.instance.runtime`
+
+### Q: What does `await runtime.apiProxy("documentSandbox")` actually do?
+
+**A:** It creates a proxy object that lets you call functions you've exposed in the document sandbox from your UI code. Think of it as getting a "remote control" for the other environment.
+
+### Q: What's the difference between `"documentSandbox"` and `"panel"` in apiProxy?
+
+**A:** These specify which environment you want to communicate with:
+- `"documentSandbox"` - Call from UI to document sandbox
+- `"panel"` - Call from document sandbox to UI
+
+### Q: Can I access document APIs directly from the UI?
+
+**A:** No, document APIs are only available in the document sandbox for security reasons. You must use the communication system to bridge between environments.
+
+### Q: How do I know which environment my code is running in?
+
+**A:** Check your file structure and imports:
+- If you're importing `addOnUISdk` β You're in the UI runtime
+- If you're importing `addOnSandboxSdk` β You're in the document sandbox
+
+### Q: Do I always need both imports in my code.js file?
+
+**A:** No! It depends on what your add-on does:
+
+- **Communication only**: Just `addOnSandboxSdk` (no document changes)
+- **Document only**: Just `express-document-sdk` (no UI communication)
+- **Both**: Most add-ons need both for UI-triggered document operations
+
+### Q: Why do some examples show one import and others show both?
+
+**A:** Different add-on types have different needs:
+- Simple document manipulation β One import
+- UI-controlled document changes β Both imports
+- The example context determines which imports are shown
+
+### Q: What else is available in the add-on-sdk-document-sandbox package?
+
+**A:** Besides `runtime`, the sandbox SDK provides:
+- **Web APIs**: Limited browser APIs like `console` for debugging
+- **Automatic global injections**: No need to import basic APIs
+- **Secure execution environment**: Isolated JavaScript context
+
+## Related Topics
+
+- [Communication APIs Reference](../../../references/document-sandbox/communication/index.md)
+- [UI SDK Reference](../../../references/addonsdk/index.md)
+- [Document API Concepts](./document-api.md)
+
+## Next Steps
+
+Now that you understand the architecture, explore these guides and tutorials:
+
+- [Document API deep dive](./document-api.md): Learn how to use the Document API to create and modify document content.
+- [Building your first add-on](../how_to/tutorials/grids-addon.md): Use the Document API to create a simple add-on that adds a grid to the document.
+- [Using the Communication APIs](../how_to/tutorials/stats-addon.md): Build an add-on to gather statistics on the active document using the Communication APIs.
diff --git a/src/pages/guides/learn/platform_concepts/terminology.md b/src/pages/guides/learn/platform_concepts/terminology.md
new file mode 100644
index 000000000..718dc9086
--- /dev/null
+++ b/src/pages/guides/learn/platform_concepts/terminology.md
@@ -0,0 +1,149 @@
+# Terminology
+
+## **Terminology Summary: Add-on UI SDK vs Document SDK vs Document APIs**
+
+### **1. Add-on UI SDK**
+**Developer Import:** `"https://new.express.adobe.com/static/add-on-sdk/sdk.js"`
+
+**What it is:** The UI runtime environment for add-ons
+- **Purpose:** Application interaction, UI management, document-level operations
+- **Runtime:** Iframe-based UI environment
+- **API Style:** Method-based, Promise-driven
+- **Example Usage:** `addOnUISdk.app.document.addImage()`, `addOnUISdk.app.showModalDialog()`
+
+### **2. Document SDK**
+**Developer Import:** `"express-document-sdk"`
+
+**What it is:** The complete document manipulation environment
+- **Purpose:** Direct document content creation and manipulation
+- **Runtime:** Document sandbox environment
+- **API Style:** Object-oriented scenegraph manipulation
+- **Example Usage:** `editor.createRectangle()`, `new Color()`, `textNode.text = "Hello"`
+
+### **3. Document APIs**
+**Technical Clarification:** This is a **subset** of the Document SDK
+
+**What it includes:** Just the core document manipulation APIs from `"express-document-sdk"`
+- **Core APIs:** `editor`, `colorUtils`, `fonts`, `viewport`
+- **Node Classes:** `RectangleNode`, `TextNode`, `GroupNode`, etc.
+- **Utilities:** `Color`, `constants`, geometry classes
+
+## **Key Distinction for Documentation**
+
+| Term | Scope | Developer Perspective |
+|------|-------|---------------------|
+| **Add-on UI SDK** | Complete UI runtime | `import addOnUISdk from "sdk.js"` |
+| **Document SDK** | Complete document environment | `import {...} from "express-document-sdk"` |
+| **Document APIs** | Core document manipulation only | Subset of Document SDK imports |
+
+## **Recommended Usage in Documentation**
+
+- **Use "Add-on UI SDK"** when referring to UI interactions, dialogs, app-level operations
+- **Use "Document SDK"** when referring to the complete document manipulation environment
+- **Use "Document APIs"** when specifically discussing just the core manipulation methods (not the full environment)
+
+## Add-on UI SDK vs Document API
+
+The **Add-on UI SDK** provides methods for application-level operations:
+- `addOnUISdk.app.document.addImage(blob)`
+- `addOnUISdk.app.showModalDialog(options)`
+
+The **Document API** provides direct scenegraph manipulation:
+- `editor.createRectangle()`
+- `rectangle.width = 100`
+
+## **Document SDK APIs (aka Document APIs) vs Add-on UI SDK**
+
+### **Document SDK**
+**What developers import:** `"express-document-sdk"`
+
+```typescript
+// Document SDK imports - for document manipulation
+import { colorUtils, constants, editor, fonts, viewport } from "express-document-sdk";
+import type {
+ Color, GroupNode, RectangleNode, TextNode,
+ BitmapImage, MediaContainerNode
+} from "express-document-sdk";
+```
+
+**What it provides:**
+
+- **Document manipulation APIs**: `editor.createRectangle()`, `editor.createText()`
+- **Node classes**: `RectangleNode`, `TextNode`, `GroupNode`, etc.
+- **Utilities**: `colorUtils`, `fonts`, `viewport`
+- **Constants**: Document-related enums and constants
+
+### **Add-on UI SDK**
+
+**What developers import:** `"https://new.express.adobe.com/static/add-on-sdk/sdk.js"`
+
+```typescript
+// Add-on UI SDK import - for UI and app interaction
+import addOnUISdk from "https://new.express.adobe.com/static/add-on-sdk/sdk.js";
+```
+
+**What it provides:**
+
+- **Application APIs**: `addOnUISdk.app.document.addImage()`
+- **UI APIs**: `addOnUISdk.app.showModalDialog()`
+- **Event handling**: `addOnUISdk.app.on("themechange")`
+
+### **Document Sandbox Runtime**
+**What developers import:** `"add-on-sdk-document-sandbox"`
+
+```typescript
+// Document Sandbox Runtime - for communication between UI and Document
+import addOnSandboxSdk from "add-on-sdk-document-sandbox";
+const runtime = addOnSandboxSdk.instance.runtime;
+```
+
+**What it provides:**
+
+- **Communication APIs**: `runtime.exposeApi()`, `runtime.apiProxy()`
+- **Runtime management**: Handles UI β Document communication
+
+## Imports & Purpose
+
+| Term | Developer Import | Purpose |
+|------|------------------|---------|
+| **Document SDK** | `"express-document-sdk"` | Direct document manipulation |
+| **Add-on UI SDK** | `"sdk.js"` | UI and application interaction |
+| **Document Sandbox Runtime** | `"add-on-sdk-document-sandbox"` | Communication layer |
+
+
+
+
+
+
+
+
+
+## Add-on Development SDKs
+
+- **Add-on UI SDK** vs **Document API**
+- **UI SDK** vs **Document API**
+- **UI Runtime APIs** vs **Document Sandbox APIs**
+- **Iframe Runtime** vs **Document Sandbox Runtime**
+
+| Aspect | **Add-on UI SDK** | **Document API** |
+|--------|-------------------|------------------|
+| **Runtime Environment** | UI iframe (full browser) | Document Sandbox (QuickJS) |
+| **Primary Purpose** | UI interactions, app-level operations | Direct document manipulation |
+| **API Style** | Method-based, async | Object-oriented, mostly sync |
+| **What You Get** | `addOnUISdk.app.document.addImage()` | `editor.createRectangle()` |
+
+## Add-on UI SDK vs Document API
+
+The **Add-on UI SDK** provides methods for application-level operations:
+
+```js
+- `addOnUISdk.app.document.addImage(blob)`
+- `addOnUISdk.app.showModalDialog(options)`
+```
+
+The **Document API** provides direct scenegraph manipulation:
+
+```js
+- `editor.createRectangle()`
+- `rectangle.width = 100`
+```
diff --git a/src/pages/guides/learn/platform_concepts/ui-sdk-vs-document-sdk.md b/src/pages/guides/learn/platform_concepts/ui-sdk-vs-document-sdk.md
new file mode 100644
index 000000000..fdcb316ae
--- /dev/null
+++ b/src/pages/guides/learn/platform_concepts/ui-sdk-vs-document-sdk.md
@@ -0,0 +1,240 @@
+# Add-on UI SDK APIs vs Document Sandbox SDK APIs
+
+The Add-on UI SDK APIs and Document APIs in the Document Sandbox SDK provide two different ways to interact with the Adobe Express platform from your add-on, each designed for distinct use cases and interaction patterns.
+
+
+
+This guide covers the differences between the UI SDK and the Document API specifically. For more information about the other features available from the Document Sandbox (ie: Communication and Browser APIs), see the [Runtime Architecture](runtime-architecture.md) guide.
+
+## Overview
+
+- **UI SDK (addOnUISdk) APIs**: Method-based API for performing actions on documents from your add-on's UI panel
+- **Document APIs**: Object-oriented API for creating and manipulating document elements in the document sandbox
+
+## Key Architectural Differences
+
+| Aspect | UI SDK (addOnUISdk) | Document API |
+|--------|---------------------|--------------|
+| **Architecture** | Method-based interfaces | Object-oriented classes |
+| **Usage Pattern** | `await document.addImage(blob)` | `rectangle.width = 100` |
+| **Purpose** | Perform actions on existing documents | Create and manipulate document elements |
+| **Execution Context** | UI iframe | Document sandbox |
+| **API Style** | Event-driven, async method calls | Direct property manipulation |
+| **Content Control** | Add content to existing document | Create and modify individual elements |
+
+## Fundamental Differences
+
+### 1. UI SDK: Remote Control Pattern
+
+The UI SDK acts like a **remote control** for the document - you send commands to Express:
+
+```typescript
+// Method-based: Call methods to perform actions
+await addOnUISdk.app.document.addImage(blob);
+await addOnUISdk.app.document.addVideo(blob);
+await addOnUISdk.app.showModalDialog(dialogOptions);
+
+const title = await addOnUISdk.app.document.title();
+const renditions = await addOnUISdk.app.document.createRenditions(options);
+```
+
+**Mental Model:** *"Hey Express, add this image to the document"*
+
+### 2. Document API: Building Blocks Pattern
+
+The Document API gives you **direct control** over document elements like building blocks:
+
+```typescript
+// Object-oriented: Create objects and set their properties
+const rectangle = editor.createRectangle();
+rectangle.width = 100;
+rectangle.height = 50;
+rectangle.fill = solidColor;
+
+const text = editor.createText("Hello World");
+text.translation = { x: 10, y: 20 };
+
+// Add objects to the document
+editor.context.insertionParent.children.append(rectangle);
+```
+
+**Mental Model:** *"Create a rectangle, make it red, put it here"*
+
+## Use Case Comparison
+
+| Task | UI SDK (addOnUISdk) | Document API |
+|------|---------------------|--------------|
+| **Add content** | `await document.addImage(blob)` | `const img = editor.createImageContainer(bitmap)`
`parent.children.append(img)` |
+| **Set properties** | β *Can't modify after adding* | `rectangle.width = 100`
`rectangle.height = 50` |
+| **Get document info** | `await document.title()` | `const title = document.title` |
+| **Apply styling** | β *No direct styling* | `rectangle.fill = redColor`
`text.textRuns[0].fontSize = 24` |
+| **Create layouts** | β *Limited to adding content* | β
*Full layout control* |
+| **Export/Share** | β
*Built-in export methods* | β *No export capabilities* |
+
+## Content Control Approaches
+
+### UI SDK: Works with Existing Documents
+The UI SDK **adds content TO** existing documents but doesn't provide direct control over individual elements:
+
+```typescript
+// Adding content to whatever document is currently open
+await addOnUISdk.app.document.addImage(blob); // Adds to current page
+await addOnUISdk.app.document.addVideo(blob); // Adds to current page
+
+// Working with the document as a whole
+const metadata = await addOnUISdk.app.document.getPagesMetadata();
+const title = await addOnUISdk.app.document.title();
+const renditions = await addOnUISdk.app.document.createRenditions(options);
+```
+
+**Key limitation:** You can add content, but you can't directly manipulate individual shapes, text, or existing elements.
+
+### Document API: Creates and Manipulates Elements
+The Document API lets you **create new elements** and **directly control** the document structure:
+
+```typescript
+// Creating new document elements from scratch
+const rectangle = editor.createRectangle();
+const ellipse = editor.createEllipse();
+const text = editor.createText("Hello");
+
+// Modifying properties of individual elements
+rectangle.width = 200;
+rectangle.topLeftRadius = 10;
+rectangle.fill = { type: "solid", color: { red: 1, green: 0, blue: 0 } };
+
+// Controlling document structure directly
+const artboard = editor.context.insertionParent;
+artboard.children.append(rectangle);
+artboard.children.append(text);
+
+// Accessing and modifying existing elements
+const existingNodes = artboard.children;
+existingNodes.forEach(node => {
+ if (node instanceof RectangleNode) {
+ node.width *= 2; // Double the width of all rectangles
+ }
+});
+```
+
+## Event Handling
+
+### UI SDK: Application-Level Events
+
+The UI SDK provides **application and document-level events** for monitoring broad system changes:
+
+```typescript
+// React to application-wide changes
+addOnUISdk.app.on("themechange", (data) => {
+ console.log("App theme changed:", data.theme);
+});
+
+addOnUISdk.app.on("documentLinkAvailable", (data) => {
+ console.log("Document link available:", data.documentLink);
+});
+
+addOnUISdk.app.on("documentTitleChange", (data) => {
+ console.log("Document title changed:", data.documentTitle);
+});
+```
+
+### Document API: Editor-Level Events
+
+The Document API provides **editor and selection-level events** for monitoring editing interactions:
+
+```typescript
+// React to user editing actions
+const handlerId = editor.context.on("selectionChange", () => {
+ const selection = editor.context.selection;
+ console.log("Selection changed, now selected:", selection.length, "items");
+
+ // Inspect and modify selected elements
+ selection.forEach(node => {
+ if (node instanceof RectangleNode) {
+ node.fill = redColor; // Change selected rectangle color
+ }
+ });
+});
+
+// Unregister event when done
+editor.context.off("selectionChange", handlerId);
+```
+
+## Synchronous vs Asynchronous Patterns
+
+### UI SDK: Everything is Async
+The UI SDK treats **all operations** as asynchronous because it communicates across process boundaries (iframe β host app):
+
+```typescript
+// ALL operations return Promises - even simple getters
+const title = await addOnUISdk.app.document.title();
+const id = await addOnUISdk.app.document.id();
+const allowed = await addOnUISdk.app.document.exportAllowed();
+
+// Actions are async
+await addOnUISdk.app.document.addImage(blob);
+await addOnUISdk.app.document.addVideo(blob);
+
+// Metadata retrieval is async
+const pages = await addOnUISdk.app.document.getPagesMetadata(options);
+const renditions = await addOnUISdk.app.document.createRenditions(options);
+```
+
+**Why async?** Every call goes through RPC (Remote Procedure Call) to the host application.
+
+### Document API: Mostly Sync with Strategic Async
+The Document API uses **synchronous property access** for immediate operations and async only when necessary:
+
+```typescript
+// Property access is synchronous - immediate response
+const rectangle = editor.createRectangle();
+rectangle.width = 100;
+rectangle.height = 50;
+const currentWidth = rectangle.width;
+
+// Most operations are immediate
+rectangle.fill = { type: "solid", color: redColor };
+text.translation = { x: 10, y: 20 };
+artboard.children.append(rectangle);
+
+// Async ONLY for resource loading
+const bitmap = await editor.loadBitmapImage(blob);
+
+// Async edit queuing after resource loading
+await editor.queueAsyncEdit(() => {
+ const container = editor.createImageContainer(bitmap);
+ editor.context.insertionParent.children.append(container);
+});
+```
+
+**Why mostly sync?** Direct object access within the same process, async only for resource loading and edit scheduling.
+
+## Summary
+
+| Aspect | UI SDK (addOnUISdk) | Document API |
+|--------|---------------------|--------------|
+| **Purpose** | Import/export, add media, get metadata | Create layouts, modify shapes, build designs |
+| **Architecture** | Method-based interfaces | Object-oriented classes |
+| **Control Level** | Add content to existing documents | Create and modify individual elements |
+| **Execution Context** | UI iframe (cross-process) | Document sandbox (same-process) |
+| **Async Pattern** | Everything is async (RPC calls) | Mostly sync, async for resource loading |
+| **Event Scope** | Application-wide changes | Editor/selection changes |
+| **Best For** | Content import, document export, UI interactions | Layout creation, element manipulation, design tools |
+
+### When to Use Each
+
+**Use UI SDK when you need to:**
+- Import images, videos, or audio into documents
+- Export documents in various formats (PNG, PDF, PPTX, etc.)
+- Get document metadata and information
+- Show modal dialogs and UI interactions
+- Work with existing document content
+
+**Use Document API when you need to:**
+- Create new visual elements (rectangles, text, images)
+- Build complex layouts and designs
+- Modify properties of individual elements
+- Respond to user selection changes
+- Create design tools and content generators
+
+The UI SDK is like a **remote control** for Express documents, while the Document API provides **direct building blocks** for creating and manipulating visual content.
\ No newline at end of file
diff --git a/src/pages/guides/support/faq.md b/src/pages/guides/support/faq.md
index 1c283a1fc..bb02f78e9 100644
--- a/src/pages/guides/support/faq.md
+++ b/src/pages/guides/support/faq.md
@@ -86,6 +86,7 @@ contributors:
- [I'm not able to load the add-on in the browser anymore. When I click on "Connect", I get an error `ERR_CERT_AUTHORITY_INVALID`.](#im-not-able-to-load-the-add-on-in-the-browser-anymore-when-i-click-on-connect-i-get-an-error-err_cert_authority_invalid)
- [Why do I receive a "No 'Access-Control-Allow-Origin' header is present on the requested resource" error?](#why-do-i-receive-a-no-access-control-allow-origin-header-is-present-on-the-requested-resource-error)
- [What permissions are available for add-ons and how do I configure them?](#what-permissions-are-available-for-add-ons-and-how-do-i-configure-them)
+- [How do I import SDK constants correctly?](#how-do-i-import-sdk-constants-correctly)
- [Is `SharedArrayBuffer` supported?](#is-sharedarraybuffer-supported)
- [Which browsers and operating systems are currently supported?](#which-browsers-and-operating-systems-are-currently-supported)
@@ -100,7 +101,8 @@ contributors:
- [I'm trying to use a newly released feature, but it seems to be unavailable?](#im-trying-to-use-a-newly-released-feature-but-it-seems-to-be-unavailable)
- [What does it mean when an API is considered **experimental**?](#what-does-it-mean-when-an-api-is-considered-experimental)
-- [How does Adobe use my add-onβs data?](#how-does-adobe-use-my-add-ons-data)
+- [Why doesn't createPage() work? How do I add pages programmatically?](#why-doesnt-createpage-work-how-do-i-add-pages-programmatically)
+- [How does Adobe use my add-on's data?](#how-does-adobe-use-my-add-ons-data)
- [Where can I request new add-on features or suggest ideas?](#where-can-i-request-new-add-on-features-or-suggest-ideas)
### π° Distribution & Monetization
@@ -212,6 +214,28 @@ At this time, the only way to monetize is by using a third party provider, and e
Experimental APIs are those which have not been declared stable yet, and to try them, first need to set the `experimentalApis` flag to `true` in the [`requirements`](../../references/manifest/index.md#requirements) section of the [`manifest.json`](../../references/manifest/index.md). The `experimentalApis` flag is **only allowed during development** and needs to be removed during submission. Experimental APIs should never be used in any add-ons you will be distributing.
+### Why doesn't createPage() work? How do I add pages programmatically?
+
+The Adobe Express Document API uses **`addPage()`** to create new pages, not `createPage()`. This is a common confusion point for developers and LLMs familiar with other APIs.
+
+**Correct usage:**
+```js
+// β
Correct - Use addPage() with dimensions
+const newPage = editor.addPage({ width: 1080, height: 1080 });
+```
+
+**Incorrect usage:**
+```js
+// β Wrong - createPage() doesn't exist
+const newPage = editor.createPage(); // This will throw an error
+```
+
+The Document API follows a specific naming convention:
+- `create*` methods (like `createRectangle()`, `createText()`) are for basic document objects
+- `add*` methods (like `addPage()`, `addArtboard()`) are for complex structures that need special handling
+
+For comprehensive examples and best practices, see our [Manage Pages how-to guide](../learn/how_to/manage_pages.md).
+
### What are the supported mime types/file formats for exported content?
The supported file types for exported content are:
@@ -317,6 +341,25 @@ Adobe Express add-ons support several types of permissions that you configure in
For complete details on all available permissions and their usage, see the [manifest permissions documentation](../../references/manifest/index.md#entrypointspermissions) and the [add-on context guide](../learn/platform_concepts/context.md#permissions).
+### How do I import SDK constants correctly?
+
+Adobe Express SDK constants use different import patterns depending on the constant type. Some constants like `SupportedMimeTypes` require named imports, while others like `Range` support both named imports and the `addOnUISdk.constants.*` pattern.
+
+**Quick Examples:**
+```javascript
+// Named imports (required for some constants)
+import addOnUISdk, { SupportedMimeTypes, Range } from "https://new.express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Both patterns work for dual-access constants
+const currentPage = Range.currentPage;
+const currentPage = addOnUISdk.constants.Range.currentPage;
+
+// Named-only constants must be imported
+const docxType = SupportedMimeTypes.docx;
+```
+
+See the [complete import patterns guide](../../references/addonsdk/addonsdk-constants.md#import-patterns) for detailed documentation, examples, and a comprehensive list of which constants require named imports vs. support dual access.
+
### Is [`SharedArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer) supported?
No, `SharedArrayBuffer` is not currently available to use with your add-ons.
diff --git a/src/pages/references/addonsdk/addonsdk-app.md b/src/pages/references/addonsdk/addonsdk-app.md
index 52c16a977..04292d45b 100644
--- a/src/pages/references/addonsdk/addonsdk-app.md
+++ b/src/pages/references/addonsdk/addonsdk-app.md
@@ -193,6 +193,10 @@ Returns a `Promise` [`DialogResult`](#dialogresult) object with the [button type
#### Confirmation Dialog Example Usage
+
+
+#### JavaScript
+
```js
import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
@@ -217,8 +221,39 @@ async function showConfirmDialog() {
}
```
+#### TypeScript
+
+```ts
+import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Wait for the SDK to be ready
+await addOnUISdk.ready;
+
+async function showConfirmDialog(): Promise
{
+ try {
+ // Confirmation Dialog Example
+ const dialogOptions: DialogOptions = {
+ variant: Variant.confirmation,
+ title: "Enable smart Filters",
+ description:
+ "Smart filters are nondestructive and will preserve your original images.",
+ buttonLabels: { primary: "Enable", cancel: "Cancel" },
+ };
+
+ const result: DialogResult = await addOnUISdk.app.showModalDialog(dialogOptions);
+ console.log("Button type clicked " + result.buttonType);
+ } catch (error) {
+ console.log("Error showing modal dialog:", error);
+ }
+}
+```
+
#### Input Dialog Example Usage
+
+
+#### JavaScript
+
```js
import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
@@ -252,6 +287,42 @@ async function showInputDialog() {
}
```
+#### TypeScript
+
+```ts
+import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Wait for the SDK to be ready
+await addOnUISdk.ready;
+
+async function showInputDialog(): Promise {
+ try {
+ // Input Dialog Example
+ const inputDialogOptions: DialogOptions = {
+ variant: Variant.input,
+ title: "Please enter your key",
+ description: "Your API key",
+ buttonLabels: { cancel: "Cancel" },
+ field: {
+ label: "API Key",
+ placeholder: "Enter API key",
+ fieldType: FieldType.text,
+ },
+ };
+
+ const inputDialogResult: DialogResult = await addOnUISdk.app.showModalDialog(
+ inputDialogOptions
+ );
+
+ if (inputDialogResult.buttonType === ButtonType.primary) {
+ console.log("Field value " + inputDialogResult.fieldValue); // returns the input the user entered if they didn't cancel
+ }
+ } catch (error) {
+ console.log("Error showing modal dialog:", error);
+ }
+}
+```
+
See the use case implementations for an example of the [custom modal dialog](../../guides/learn/how_to/modal_dialogs.md#custom-dialog).
@@ -287,6 +358,10 @@ Returns a void `Promise`.
#### Example Usage
+
+
+#### JavaScript
+
```js
const colorPickerButton = document.getElementById("color-picker-button");
@@ -304,6 +379,27 @@ colorPickerButton.addEventListener(ColorPickerEvent.colorChange, (event) => {
});
```
+#### TypeScript
+
+```ts
+const colorPickerButton = document.getElementById("color-picker-button") as HTMLButtonElement;
+
+colorPickerButton.addEventListener("click", (): void => {
+ const options: ColorPickerOptions = {
+ title: "Add-on's Color Picker",
+ placement: ColorPickerPlacement.left,
+ eyedropperHidesPicker: true,
+ disableAlphaChannel: false,
+ };
+
+ addOnUISdk.app.showColorPicker(colorPickerButton, options);
+});
+
+colorPickerButton.addEventListener(ColorPickerEvent.colorChange, (event: CustomEvent): void => {
+ console.log("Color change event received!", event.detail.color);
+});
+```
+
### hideColorPicker()
Hides the Adobe Express color picker.
@@ -458,6 +554,100 @@ Callback to undo the changes made by `enableDragToDocument`. Returns `void`.
type DisableDragToDocument = () => void;
```
+#### Example Usage
+
+
+
+#### JavaScript
+
+```js
+import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Wait for the SDK to be ready
+await addOnUISdk.ready;
+
+// Enable drag-to-document for an image element
+const imageElement = document.getElementById("my-image");
+
+const dragCallbacks = {
+ previewCallback: (element) => {
+ // Return the preview image URL
+ return new URL(element.src);
+ },
+
+ completionCallback: async (element) => {
+ try {
+ // Fetch the image blob for drag completion
+ const response = await fetch(element.src);
+ const blob = await response.blob();
+
+ return [{
+ blob: blob,
+ attributes: {
+ title: element.alt || "Dragged Image"
+ }
+ }];
+ } catch (error) {
+ console.error("Failed to fetch image for drag:", error);
+ return [];
+ }
+ }
+};
+
+// Enable drag to document
+const disableDrag = addOnUISdk.app.enableDragToDocument(imageElement, dragCallbacks);
+
+// Later, you can disable the drag functionality
+// disableDrag();
+```
+
+#### TypeScript
+
+```ts
+import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Wait for the SDK to be ready
+await addOnUISdk.ready;
+
+// Enable drag-to-document for an image element
+const imageElement = document.getElementById("my-image") as HTMLImageElement;
+
+const dragCallbacks: DragCallbacks = {
+ previewCallback: (element: HTMLElement): URL => {
+ // Return the preview image URL
+ const imgElement = element as HTMLImageElement;
+ return new URL(imgElement.src);
+ },
+
+ completionCallback: async (element: HTMLElement): Promise => {
+ try {
+ // Fetch the image blob for drag completion
+ const imgElement = element as HTMLImageElement;
+ const response = await fetch(imgElement.src);
+ const blob: Blob = await response.blob();
+
+ const completionData: DragCompletionData[] = [{
+ blob: blob,
+ attributes: {
+ title: imgElement.alt || "Dragged Image"
+ }
+ }];
+
+ return completionData;
+ } catch (error) {
+ console.error("Failed to fetch image for drag:", error);
+ return [];
+ }
+ }
+};
+
+// Enable drag to document
+const disableDrag: DisableDragToDocument = addOnUISdk.app.enableDragToDocument(imageElement, dragCallbacks);
+
+// Later, you can disable the drag functionality
+// disableDrag();
+```
+
##### `DragStartEventData` Object
The payload data sent to the `dragStart` event handler.
diff --git a/src/pages/references/addonsdk/addonsdk-constants.md b/src/pages/references/addonsdk/addonsdk-constants.md
index ba11aab2b..30f4cd600 100644
--- a/src/pages/references/addonsdk/addonsdk-constants.md
+++ b/src/pages/references/addonsdk/addonsdk-constants.md
@@ -1,8 +1,275 @@
# addOnUISdk.constants
-A set of constants used throughout the add-on SDK. These constants are equal to their variable name as a string value, ie: for the `ButtonType` constant, `primary` has a value of "primary".
+This reference covers set of constants used throughout the Add-on UI SDK, including:
-## Constants
+- Constants available in `addOnUISdk.constants.*` (dual access)
+- Constants available only as named exports (import required)
+
+See the [Import Patterns](#import-patterns) section for details on how to access each type.
+
+
+
+The constants listed in this reference are equal to their variable name as a string value, ie: for the `ButtonType` constant, `primary` has a value of "primary".
+
+## Import Patterns
+
+Adobe Express Add-on SDK constants are available through different import patterns depending on the constant type. Understanding these patterns is imperative for avoiding runtime errors.
+
+### Named Exports (Import Required)
+
+These constants are **only available as named exports** and must be imported explicitly. They are **not** available through `addOnUISdk.constants.*`:
+
+```javascript
+import addOnUISdk, {
+ AppEvent,
+ ColorPickerEvent,
+ SupportedMimeTypes,
+ EntrypointType,
+ PdfReturnUrlType
+} from "https://new.express.adobe.com/static/add-on-sdk/sdk.js";
+
+// β
Correct usage
+const docxMimeType = SupportedMimeTypes.docx;
+const colorChangeEvent = ColorPickerEvent.colorChange;
+
+// β Will NOT work - these are not in the constants object
+const docxMimeType = addOnUISdk.constants.SupportedMimeTypes.docx; // undefined
+```
+
+### Dual Access Constants
+
+These constants support **both import patterns** for flexibility. You can use either approach:
+
+```javascript
+import addOnUISdk, { Range, RenditionFormat, Variant } from "https://new.express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Option 1: Named import (recommended for cleaner code)
+const currentPage = Range.currentPage;
+const pngFormat = RenditionFormat.png;
+const confirmDialog = Variant.confirmation;
+
+// Option 2: Constants object access (traditional pattern)
+const currentPage = addOnUISdk.constants.Range.currentPage;
+const pngFormat = addOnUISdk.constants.RenditionFormat.png;
+const confirmDialog = addOnUISdk.constants.Variant.confirmation;
+```
+
+**Dual Access Constants List:**
+
+- `Range` / `addOnUISdk.constants.Range`
+- `RenditionFormat` / `addOnUISdk.constants.RenditionFormat`
+- `RenditionType` / `addOnUISdk.constants.RenditionType`
+- `RenditionIntent` / `addOnUISdk.constants.RenditionIntent`
+- `Variant` / `addOnUISdk.constants.Variant`
+- `DialogResultType` / `addOnUISdk.constants.DialogResultType`
+- `ButtonType` / `addOnUISdk.constants.ButtonType`
+- `RuntimeType` / `addOnUISdk.constants.RuntimeType`
+- `BleedUnit` / `addOnUISdk.constants.BleedUnit`
+- `EditorPanel` / `addOnUISdk.constants.EditorPanel`
+- `MediaTabs` / `addOnUISdk.constants.MediaTabs`
+- `ElementsTabs` / `addOnUISdk.constants.ElementsTabs`
+- `PanelActionType` / `addOnUISdk.constants.PanelActionType`
+- `ColorPickerPlacement` / `addOnUISdk.constants.ColorPickerPlacement`
+- `AuthorizationStatus` / `addOnUISdk.constants.AuthorizationStatus`
+- `FieldType` / `addOnUISdk.constants.FieldType`
+- `PlatformEnvironment` / `addOnUISdk.constants.PlatformEnvironment`
+- `DeviceClass` / `addOnUISdk.constants.DeviceClass`
+- `PlatformType` / `addOnUISdk.constants.PlatformType`
+- `MediaType` / `addOnUISdk.constants.MediaType`
+- `VideoResolution` / `addOnUISdk.constants.VideoResolution`
+- `FrameRate` / `addOnUISdk.constants.FrameRate`
+- `BitRate` / `addOnUISdk.constants.BitRate`
+- `FileSizeLimitUnit` / `addOnUISdk.constants.FileSizeLimitUnit`
+- `LinkOptions` / `addOnUISdk.constants.LinkOptions`
+
+
+### Best Practices
+
+1. **Use named imports for cleaner code** when you know which constants you need:
+ ```javascript
+ import addOnUISdk, { Range, RenditionFormat } from "https://new.express.adobe.com/static/add-on-sdk/sdk.js";
+
+ const options = {
+ range: Range.currentPage,
+ format: RenditionFormat.png
+ };
+ ```
+
+2. **Use constants object for dynamic access** when the constant name is determined at runtime:
+ ```javascript
+ const format = addOnUISdk.constants.RenditionFormat[userSelectedFormat];
+ ```
+
+3. **Always import named-only exports** - there's no alternative way to access them:
+ ```javascript
+ import addOnUISdk, { SupportedMimeTypes } from "https://new.express.adobe.com/static/add-on-sdk/sdk.js";
+ ```
+
+### Quick Reference Table
+
+| Constant | Named Export | Constants Object | Import Required |
+|----------|--------------|------------------|-----------------|
+| `AppEvent` | β
| β | **Yes** |
+| `ColorPickerEvent` | β
| β | **Yes** |
+| `SupportedMimeTypes` | β
| β | **Yes** |
+| `EntrypointType` | β
| β | **Yes** |
+| `PdfReturnUrlType` | β
| β | **Yes** |
+| `Range` | β
| β
| Optional |
+| `RenditionFormat` | β
| β
| Optional |
+| `Variant` | β
| β
| Optional |
+| `ButtonType` | β
| β
| Optional |
+| `FieldType` | β
| β
| Optional |
+| `PlatformEnvironment` | β
| β
| Optional |
+| `DeviceClass` | β
| β
| Optional |
+| `PlatformType` | β
| β
| Optional |
+| `AuthorizationStatus` | β
| β
| Optional |
+| `RenditionType` | β
| β
| Optional |
+| `RenditionIntent` | β
| β
| Optional |
+| `DialogResultType` | β
| β
| Optional |
+| `RuntimeType` | β
| β
| Optional |
+| `BleedUnit` | β
| β
| Optional |
+| `EditorPanel` | β
| β
| Optional |
+| `MediaTabs` | β
| β
| Optional |
+| `ElementsTabs` | β
| β
| Optional |
+| `PanelActionType` | β
| β
| Optional |
+| `ColorPickerPlacement` | β
| β
| Optional |
+| `MediaType` | β
| β
| Optional |
+| `VideoResolution` | β
| β
| Optional |
+| `FrameRate` | β
| β
| Optional |
+| `BitRate` | β
| β
| Optional |
+| `FileSizeLimitUnit` | β
| β
| Optional |
+| `LinkOptions` | β
| β
| Optional |
+
+
+
+
+**Important:** Attempting to access named-only exports through `addOnUISdk.constants.*` will return `undefined` and may cause runtime errors. Always check the table above or use TypeScript for compile-time validation.
+
+## Add-on UI SDK Constants
+
+### **Dialog & UI Interaction Constants**
+
+| Constant | Values | Description | Usage |
+|----------|--------|-------------|-------|
+| **`Variant`** | `confirmation`, `information`, `warning`, `destructive`, `error`, `input`, `custom` | Dialog types for `showModalDialog()` | `addOnUISdk.app.showModalDialog({variant: Variant.error})` |
+| **`ButtonType`** | `primary`, `secondary`, `cancel`, `close` | Button types in dialog responses | Check `result.buttonType === ButtonType.primary` |
+| **`FieldType`** | `text` | Input field types for input dialogs | Used in dialog field configuration |
+| **`DialogResultType`** | `alert`, `input`, `custom` | Types of dialog results returned | Determine result structure type |
+
+### **Platform & Environment Constants**
+
+| Constant | Values | Description | Usage |
+|----------|--------|-------------|-------|
+| **`PlatformType`** | `iOS`, `iPadOS`, `chromeOS`, `android`, `chromeBrowser`, `firefoxBrowser`, `edgeBrowser`, `samsungBrowser`, `safariBrowser`, `unknown` | Platform identification | `platform.platformType === PlatformType.iOS` |
+| **`PlatformEnvironment`** | `app`, `web` | Runtime environment type | Check if running in app vs web |
+| **`DeviceClass`** | `mobile`, `tablet`, `desktop` | Device category | Responsive design decisions |
+| **`RuntimeType`** | `panel`, `dialog`, `documentSandbox`, `command` | Add-on runtime types | Communication API configuration |
+| **`EntrypointType`** | `WIDGET`, `COMMAND`, `SCRIPT`, `PANEL`, `SHARE`, `CONTENT_HUB`, `MOBILE_MEDIA_AUDIO`, `MOBILE_YOUR_STUFF_FILES`, `MOBILE_MORE`, `SCHEDULE`, `CONTEXTUAL_REPLACE`, `CONTEXTUAL_UPLOAD`, `CONTEXTUAL_BULK_CREATE` | Types of add-on entrypoints | `addOn.entrypointType === EntrypointType.PANEL` |
+
+### **Document Export & Rendering Constants**
+
+| Constant | Values | Description | Usage |
+|----------|--------|-------------|-------|
+| **`Range`** | `currentPage`, `entireDocument`, `specificPages` | Rendition page ranges | `createRenditions({range: Range.currentPage})` |
+| **`RenditionFormat`** | `png`, `jpg`, `mp4`, `pdf`, `pptx` | Export file formats | Specify output format for renditions |
+| **`RenditionType`** | `page` | Type of rendition | Document export configuration |
+| **`RenditionIntent`** | `export`, `preview`, `print` | Purpose of rendition | Optimize rendering for use case |
+
+### **Video & Media Constants**
+
+| Constant | Values | Description | Usage |
+|----------|--------|-------------|-------|
+| **`VideoResolution`** | `sd480p`, `hd720p`, `fhd1080p`, `qhd1440p`, `uhd2160p`, `custom` | Video export resolutions | Video rendition quality settings |
+| **`FrameRate`** | `fps23_976`, `fps24`, `fps25`, `fps29_97`, `fps30`, `fps60` | Video frame rates | Video export frame rate |
+| **`BitRate`** | `mbps4`, `mbps8`, `mbps10`, `mbps12`, `mbps15`, `mbps25`, `mbps50` | Video bit rates in Mbps | Video compression settings |
+
+### **Print & Layout Constants**
+
+| Constant | Values | Description | Usage |
+|----------|--------|-------------|-------|
+| **`BleedUnit`** | `Inch`, `Millimeter` | Print bleed units | Print preparation |
+
+### **Editor Panel Navigation Constants**
+
+| Constant | Values | Description | Usage |
+|----------|--------|-------------|-------|
+| **`EditorPanel`** | `search`, `yourStuff`, `templates`, `media`, `text`, `elements`, `grids`, `brands`, `addOns` | Express editor panels | `openEditorPanel(EditorPanel.media)` |
+| **`MediaTabs`** | `video`, `audio`, `photos` | Media panel tabs | Navigate to specific media type |
+| **`ElementsTabs`** | `designAssets`, `backgrounds`, `shapes`, `stockIcons`, `charts` | Elements panel tabs | Navigate to specific element type |
+| **`PanelActionType`** | `search`, `navigate` | Panel action types | Panel interaction configuration |
+
+### **Color Picker Constants**
+
+| Constant | Values | Description | Usage |
+|----------|--------|-------------|-------|
+| **`ColorPickerPlacement`** | `top`, `bottom`, `left`, `right` | Color picker positioning | `showColorPicker(element, {placement: ColorPickerPlacement.top})` |
+
+### **Event Constants**
+
+| Constant | Values | Description | Usage |
+|----------|--------|-------------|-------|
+| **`AppEvent`** | `documentIdAvailable`, `documentTitleChange`, `documentLinkAvailable`, `documentPublishedLinkAvailable`, `themechange`, `localechange`, `formatchange`, `reset`, `dragstart`, `dragend`, `dragcancel`, `documentExportAllowedChange` | Events dispatched by the Add-on SDK | `addOnUISdk.app.on(AppEvent.themechange, handler)` |
+| **`ColorPickerEvent`** | `colorChange`, `close` | Custom events dispatched by the Color Picker | Listen for color picker events on anchor element |
+
+### **File Management Constants**
+
+| Constant | Values | Description | Usage |
+|----------|--------|-------------|-------|
+| **`SupportedMimeTypes`** | `docx`, `gdoc` | MIME types for original source assets converted to PDF | File import validation |
+| **`PdfReturnUrlType`** | `cdnUrl`, `jumpUrl` | Type of URL returned for PDF rendition export | PDF export configuration |
+| **`MediaType`** | `Audio` | Media type identifiers | Media handling and processing |
+| **`FileSizeLimitUnit`** | `KB`, `MB` | File size limit units | File upload constraints |
+| **`LinkOptions`** | `document`, `published` | Types of document links available | `addOnUISdk.app.document.link(LinkOptions.published)` |
+
+### **OAuth & Authentication Constants**
+
+| Constant | Values | Description | Usage |
+|----------|--------|-------------|-------|
+| **`AuthorizationStatus`** | `SUCCESS`, `POPUP_OPENED`, `POPUP_BLOCKED`, `POPUP_CLOSED`, `POPUP_TIMEOUT`, `FAILED`, `IFRAME_LOAD_FAILED` | OAuth authorization workflow status values | `result.status === AuthorizationStatus.SUCCESS` |
+
+### **Usage Examples**
+
+```typescript
+import addOnUISdk, {
+ Variant,
+ PlatformType,
+ RenditionFormat,
+ EditorPanel
+} from "https://new.express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Dialog with error variant
+await addOnUISdk.app.showModalDialog({
+ variant: Variant.error,
+ title: "Upload Failed",
+ description: "File size exceeds limit"
+});
+
+// Platform-specific behavior
+const platform = await addOnUISdk.app.getCurrentPlatform();
+if (platform.platformType === PlatformType.iOS) {
+ // iOS-specific handling
+}
+
+// Export document as PNG
+await addOnUISdk.app.document.createRenditions({
+ format: RenditionFormat.png,
+ range: Range.currentPage
+});
+
+// Navigate to media panel
+addOnUISdk.app.ui.openEditorPanel(EditorPanel.media);
+```
+
+### **Notes for Developers**
+
+- **All constants are available as named exports** from the Add-on UI SDK
+- **Use constants instead of string literals** for type safety and future compatibility
+- **Some constants are marked as `@internal`** (like `ToastVariant`, `FeatureType`, `SettingType`) and are not included as they're for internal/privileged use only
+- **Platform detection is crucial** for responsive add-on design across different devices and browsers
+
+These constants provide type-safe ways to interact with all the major Add-on UI SDK features that third-party developers commonly use!
+
+
diff --git a/src/pages/references/addonsdk/addonsdk-instance.md b/src/pages/references/addonsdk/addonsdk-instance.md
index 8b205046b..4ecfb237c 100644
--- a/src/pages/references/addonsdk/addonsdk-instance.md
+++ b/src/pages/references/addonsdk/addonsdk-instance.md
@@ -1,6 +1,6 @@
# addOnUISdk.instance
-Represents the currently running add-on instance. This object is used to provide access to the `clientStorage` and `manifest` objects. See the [Storing and Retrieving Client Side Data](../../guides/learn/how_to/local_data_management.md) use case implementation and [Manifest](../manifest) reference for more details.
+Represents the currently running add-on instance. This object is used to provide access to the `clientStorage`, `manifest`, and `runtime` objects. See the [Storing and Retrieving Client Side Data](../../guides/learn/how_to/local_data_management.md) use case implementation and [Manifest](../manifest) reference for more details.
## Objects
diff --git a/src/pages/references/addonsdk/app-document.md b/src/pages/references/addonsdk/app-document.md
index d18269e00..050a727b6 100644
--- a/src/pages/references/addonsdk/app-document.md
+++ b/src/pages/references/addonsdk/app-document.md
@@ -92,7 +92,7 @@ A resolved `Promise` containing a [`PageMetadata`](#pagemetadata) array containi
#### Example Usage
-
+
#### JavaScript
@@ -135,6 +135,49 @@ async function logMetadata() {
}
```
+#### TypeScript
+
+```ts
+import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Wait for the SDK to be ready
+await addOnUISdk.ready;
+
+// Get metadata of all the pages
+async function logMetadata(): Promise {
+ try {
+ const options: PageMetadataOptions = {
+ range: Range.specificPages,
+ pageIds: [
+ "7477a5e7-02b2-4b8d-9bf9-f09ef6f8b9fc",
+ "d45ba3fc-a3df-4a87-80a5-655e5f8f0f96"
+ ]
+ };
+
+ const pages: PageMetadata[] = await addOnUISdk.app.document.getPagesMetadata(options);
+
+ for (const page of pages) {
+ console.log("Page id: ", page.id);
+ console.log("Page title: ", page.title);
+ console.log("Page size: ", page.size);
+ console.log("Page has premium content: ", page.hasPremiumContent);
+ console.log("Page has audio content: ", page.hasAudioContent);
+ console.log("Page has video content: ", page.hasVideoContent);
+ console.log("Page has animated content: ", page.hasAnimatedContent);
+ console.log("Page has timelines: ", page.hasTemporalContent);
+ if (page.hasTemporalContent)
+ console.log("Page includes temporal content with a duration of: ", page.temporalContentDuration);
+ console.log("Pixels per inch: ", page.pixelsPerInch);
+ console.log("Is page print ready: ", page.isPrintReady);
+ console.log("Is page blank: ", page.isBlank);
+ console.log("Template details: ", page.templateDetails);
+ }
+ } catch (error) {
+ console.log("Failed to get metadata:", error);
+ }
+}
+```
+
#### Output
```bash
@@ -177,7 +220,7 @@ Tells Express to run a print quality check to determine if the document is ready
#### Example Usage
-
+
#### JavaScript
@@ -200,6 +243,44 @@ function runPrintQualityCheck() {
}
```
+#### TypeScript
+
+```ts
+import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Reference to the active document
+const { document } = addOnUISdk.app;
+
+// Run Print Quality Check
+function runPrintQualityCheck(): void {
+ try {
+ const options: PrintQualityCheckOptions = {
+ range: Range.entireDocument,
+ };
+
+ document.runPrintQualityCheck(options);
+ console.log("Print quality check completed successfully");
+ } catch (error) {
+ console.log("Failed to run print quality check");
+ }
+}
+
+// Run Print Quality Check for specific pages
+function runPrintQualityCheckForPages(pageIds: string[]): void {
+ try {
+ const options: PrintQualityCheckOptions = {
+ range: Range.specificPages,
+ pageIds: pageIds
+ };
+
+ document.runPrintQualityCheck(options);
+ console.log("Print quality check completed successfully for specific pages");
+ } catch (error) {
+ console.log("Failed to run print quality check for specific pages");
+ }
+}
+```
+
#### Output
```bash
@@ -267,7 +348,11 @@ A resolved `Promise` containing an array of `string` ids representing the curren
#### Example Usage
-```javascript
+
+
+#### JavaScript
+
+```js
import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
// Wait for the SDK to be ready
@@ -316,6 +401,59 @@ getSelectedPages();
getSelectedPagesMetadata();
```
+#### TypeScript
+
+```ts
+import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Wait for the SDK to be ready
+await addOnUISdk.ready;
+
+// Get the currently selected page ids
+async function getSelectedPages(): Promise {
+ try {
+ const selectedPageIds: string[] = await addOnUISdk.app.document.getSelectedPageIds();
+ console.log("Selected page ids:", selectedPageIds);
+
+ if (selectedPageIds.length === 0) {
+ console.log("No pages are currently selected");
+ } else {
+ console.log(`${selectedPageIds.length} page(s) selected:`, selectedPageIds);
+ }
+ } catch (error) {
+ console.log("Failed to get selected page ids:", error);
+ }
+}
+
+// Example: Get metadata for selected pages only
+async function getSelectedPagesMetadata(): Promise {
+ try {
+ const selectedPageIds: string[] = await addOnUISdk.app.document.getSelectedPageIds();
+
+ if (selectedPageIds.length > 0) {
+ const options: PageMetadataOptions = {
+ range: Range.specificPages,
+ pageIds: selectedPageIds
+ };
+
+ const metadata: PageMetadata[] = await addOnUISdk.app.document.getPagesMetadata(options);
+
+ metadata.forEach((page: PageMetadata, index: number) => {
+ console.log(`Selected page ${index + 1}: ${page.title} (${page.id})`);
+ });
+ } else {
+ console.log("No pages selected");
+ }
+ } catch (error) {
+ console.log("Failed to get selected pages metadata:", error);
+ }
+}
+
+// Call the functions
+getSelectedPages();
+getSelectedPagesMetadata();
+```
+
### link()
Retrieves the document link.
@@ -571,12 +709,21 @@ Mime type details for importing media
| Name | Type | Description |
| ----------------- | -------------------------- | ---------------------------------------------------------------: |
-| `sourceMimeType?` | [`SupportedMimeTypes`](./) | Mime type of the original source asset that was converted to PDF |
+| `sourceMimeType?` | [`SupportedMimeTypes`](#supportedmimetypes) | Mime type of the original source asset that was converted to PDF |
### SupportedMimeTypes
-A constant representing the mime type of the original source asset that was converted to PDF.
+A constant representing the mime type of the original source asset that was converted to PDF. **Note:** This constant is only available as a named export and must be imported explicitly.
+
+```javascript
+import addOnUISdk, { SupportedMimeTypes } from "https://new.express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Usage
+const docxMimeType = SupportedMimeTypes.docx;
+const gdocMimeType = SupportedMimeTypes.gdoc;
+```
+Available values:
- **docx**: `"docx"`
- **gdoc**: `"gdoc"`
diff --git a/src/pages/references/addonsdk/app-oauth.md b/src/pages/references/addonsdk/app-oauth.md
index d090a52cc..22bbf2a4b 100644
--- a/src/pages/references/addonsdk/app-oauth.md
+++ b/src/pages/references/addonsdk/app-oauth.md
@@ -42,6 +42,86 @@ A resolved `Promise` with the [`AuthorizationResponse`](#authorizationresponse)
| `redirectUri` | `string` | URL where the user is redirected to after authorization. This is the default URL owned by Adobe and it is this URL which needs to be used to obtain access_token. |
| `result` | `string` or `object` | An [`AuthorizationResult`](#authorizationresult) payload which denotes either success or failure. In the event of a "FAILED" status reported by the OAuth provider during authorization, the value of this property is an `object`, in the form of `{[failure_title]: "failure_description"}`, and for all other statuses the value of `description` is a `string`. |
+#### Example Usage
+
+
+
+#### JavaScript
+
+```js
+import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Wait for the SDK to be ready
+await addOnUISdk.ready;
+
+async function handleOAuthAuthorization() {
+ try {
+ const authRequest = {
+ authorizationUrl: "https://api.example.com/oauth/authorize",
+ clientId: "your-client-id",
+ scope: "read write",
+ codeChallenge: "generated-code-challenge",
+ additionalParameters: new Map([
+ ["response_type", "code"],
+ ["access_type", "offline"]
+ ]),
+ windowSize: { width: 600, height: 700 }
+ };
+
+ const response = await addOnUISdk.app.oauth.authorize(authRequest);
+
+ if (response.result.status === "SUCCESS") {
+ console.log("Authorization successful!");
+ console.log("Authorization code:", response.code);
+ console.log("Redirect URI:", response.redirectUri);
+ // Use the authorization code to get access token
+ } else {
+ console.log("Authorization failed:", response.result.description);
+ }
+ } catch (error) {
+ console.log("OAuth error:", error);
+ }
+}
+```
+
+#### TypeScript
+
+```ts
+import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Wait for the SDK to be ready
+await addOnUISdk.ready;
+
+async function handleOAuthAuthorization(): Promise {
+ try {
+ const authRequest: AuthorizationRequest = {
+ authorizationUrl: "https://api.example.com/oauth/authorize",
+ clientId: "your-client-id",
+ scope: "read write",
+ codeChallenge: "generated-code-challenge",
+ additionalParameters: new Map([
+ ["response_type", "code"],
+ ["access_type", "offline"]
+ ]),
+ windowSize: { width: 600, height: 700 }
+ };
+
+ const response: AuthorizationResponse = await addOnUISdk.app.oauth.authorize(authRequest);
+
+ if (response.result.status === AuthorizationStatus.authorized) {
+ console.log("Authorization successful!");
+ console.log("Authorization code:", response.code);
+ console.log("Redirect URI:", response.redirectUri);
+ // Use the authorization code to get access token
+ } else {
+ console.log("Authorization failed:", response.result.description);
+ }
+ } catch (error) {
+ console.log("OAuth error:", error);
+ }
+}
+```
+
### authorizeWithOwnRedirect()
Initiate the OAuth 2.0 PKCE authorization workflow by opening the user sign-in window. After authorization, the user is redirected to the add-on developer provided URL.
@@ -80,6 +160,204 @@ A resolved `Promise` with the [`AuthorizationResult`](#authorizationresult) obje
| `status` | `AuthorizationStatus` | Status representing success or failure in the authorization workflow. |
| `description` | `string` or `object` | Description about the success or failure in the authorization workflow In the event of a "FAILED" status reported by the OAuth provider during authorization, the value of this property is an `object`, in the form of `{[failure_title]: "failure_description"}`. While for all other statuses the value of this property is a `string` |
+#### Example Usage
+
+
+
+#### JavaScript
+
+```js
+import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Wait for the SDK to be ready
+await addOnUISdk.ready;
+
+async function handleOAuthWithRedirect() {
+ try {
+ const authRequest = {
+ authorizationUrl: "https://api.example.com/oauth/authorize",
+ clientId: "your-client-id",
+ scope: "read write",
+ codeChallenge: "generated-code-challenge",
+ redirectUri: "https://yourapp.com/oauth/callback",
+ state: "random-state-value",
+ additionalParameters: new Map([
+ ["response_type", "code"],
+ ["access_type", "offline"]
+ ]),
+ windowSize: { width: 600, height: 700 }
+ };
+
+ const result = await addOnUISdk.app.oauth.authorizeWithOwnRedirect(authRequest);
+
+ if (result.status === "POPUP_OPENED") {
+ console.log("Authorization popup opened successfully");
+ console.log("Handle the redirect at your callback URL:", authRequest.redirectUri);
+ } else {
+ console.log("Authorization failed:", result.description);
+ }
+ } catch (error) {
+ console.log("OAuth error:", error);
+ }
+}
+```
+
+#### TypeScript
+
+```ts
+import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Wait for the SDK to be ready
+await addOnUISdk.ready;
+
+async function handleOAuthWithRedirect(): Promise {
+ try {
+ const authRequest: AuthorizeWithOwnRedirectRequest = {
+ authorizationUrl: "https://api.example.com/oauth/authorize",
+ clientId: "your-client-id",
+ scope: "read write",
+ codeChallenge: "generated-code-challenge",
+ redirectUri: "https://yourapp.com/oauth/callback",
+ state: "random-state-value",
+ additionalParameters: new Map([
+ ["response_type", "code"],
+ ["access_type", "offline"]
+ ]),
+ windowSize: { width: 600, height: 700 }
+ };
+
+ const result: AuthorizationResult = await addOnUISdk.app.oauth.authorizeWithOwnRedirect(authRequest);
+
+ if (result.status === AuthorizationStatus.cancelled) {
+ console.log("Authorization popup opened successfully");
+ console.log("Handle the redirect at your callback URL:", authRequest.redirectUri);
+ } else {
+ console.log("Authorization failed:", result.description);
+ }
+ } catch (error) {
+ console.log("OAuth error:", error);
+ }
+}
+```
+
+### authorizeInsideIframe()
+
+Authorize a user using OAuth 2.0 PKCE workflow in an iframe. This method provides an alternative to popup-based authorization for cases where popups may be blocked or when you prefer an iframe-based flow.
+
+#### Signature:
+
+`authorizeInsideIframe(request: AuthorizeInsideIframeRequest): Promise`
+
+#### Parameters
+
+| Name | Type | Description |
+| --------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------: |
+| `request` | `object` | [`AuthorizeInsideIframeRequest`](#authorizeinsideiframerequest) object payload with parameters to be used in the authorization workflow. |
+
+#### `AuthorizeInsideIframeRequest`
+
+Extends [`AuthorizationRequest`](#authorizationrequest) with additional properties specific to iframe-based OAuth flows.
+
+| Name | Type | Description |
+| ----------------------- | ----------------------------------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| `authorizationUrl` | `string` | OAuth provider's authorization URL. |
+| `clientId` | `string` | Client identifier of the application created at the OAuth provider. |
+| `scope` | `string` | Scope to control the application's access. |
+| `codeChallenge` | `string` | Code challenge used in Authorization Code Exchange. |
+| `additionalParameters?` | `Map` | Additional parameters, specific to an OAuth provider which are required in the Authorization URL as query string parameters. |
+| `windowSize?` | `{ width: number; height: number }` | The authorization iframe size in the form of an `object` containing the desired `width` and `height` as a `number`.
**NOTE:** The **minimum** (and **default**) values for `windowSize` are 480 x 480. The **maximum** allowed values are 800 x (screen height). |
+| `position?` | `{ top: number; left: number }` | Relative position of the OAuth iframe panel. |
+| `offset?` | `{ right: number; bottom: number }` | Offset from the right and bottom of the iframe container when the size (`windowSize`) is not specified. |
+| `showHeader?` | `boolean` | Flag to determine if the iframe panel needs to show a header. |
+
+#### Return Value
+
+A resolved `Promise` with the [`AuthorizationResponse`](#authorizationresponse) object, which contains the authorization code, redirect URI, and result status.
+
+#### Example Usage
+
+
+
+#### JavaScript
+
+```js
+import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Wait for the SDK to be ready
+await addOnUISdk.ready;
+
+async function handleOAuthInsideIframe() {
+ try {
+ const authRequest = {
+ authorizationUrl: "https://api.example.com/oauth/authorize",
+ clientId: "your-client-id",
+ scope: "read write",
+ codeChallenge: "generated-code-challenge",
+ additionalParameters: new Map([
+ ["response_type", "code"],
+ ["access_type", "offline"]
+ ]),
+ windowSize: { width: 600, height: 700 },
+ position: { top: 100, left: 100 },
+ showHeader: true
+ };
+
+ const response = await addOnUISdk.app.oauth.authorizeInsideIframe(authRequest);
+
+ if (response.result.status === "SUCCESS") {
+ console.log("Authorization successful!");
+ console.log("Authorization code:", response.code);
+ console.log("Redirect URI:", response.redirectUri);
+ // Use the authorization code to get access token
+ } else {
+ console.log("Authorization failed:", response.result.description);
+ }
+ } catch (error) {
+ console.log("OAuth error:", error);
+ }
+}
+```
+
+#### TypeScript
+
+```ts
+import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
+
+// Wait for the SDK to be ready
+await addOnUISdk.ready;
+
+async function handleOAuthInsideIframe(): Promise {
+ try {
+ const authRequest: AuthorizeInsideIframeRequest = {
+ authorizationUrl: "https://api.example.com/oauth/authorize",
+ clientId: "your-client-id",
+ scope: "read write",
+ codeChallenge: "generated-code-challenge",
+ additionalParameters: new Map([
+ ["response_type", "code"],
+ ["access_type", "offline"]
+ ]),
+ windowSize: { width: 600, height: 700 },
+ position: { top: 100, left: 100 },
+ showHeader: true
+ };
+
+ const response: AuthorizationResponse = await addOnUISdk.app.oauth.authorizeInsideIframe(authRequest);
+
+ if (response.result.status === AuthorizationStatus.authorized) {
+ console.log("Authorization successful!");
+ console.log("Authorization code:", response.code);
+ console.log("Redirect URI:", response.redirectUri);
+ // Use the authorization code to get access token
+ } else {
+ console.log("Authorization failed:", response.result.description);
+ }
+ } catch (error) {
+ console.log("OAuth error:", error);
+ }
+}
+```
+
#### `AuthorizationStatus`
Each of the statuses returned below is the exact name as a string (ie: SUCCESS = "SUCCESS")
diff --git a/src/pages/references/addonsdk/index.md b/src/pages/references/addonsdk/index.md
index f00603c5c..f7c80a4e1 100644
--- a/src/pages/references/addonsdk/index.md
+++ b/src/pages/references/addonsdk/index.md
@@ -87,6 +87,10 @@ The SDK can be referenced in `.js/.jsx/.ts/.tsx` source files by adding it to th
import addOnUISdk from "https://express.adobe.com/static/add-on-sdk/sdk.js";
```
+
+
+**π¦ Working with SDK Constants:** Adobe Express SDK constants use different import patterns. Some require named imports while others support both approaches. See the [complete import patterns guide](./addonsdk-constants.md#import-patterns) for details and examples.
+
**Note:** if you created your add-on project with the CLI based on the `typescript` or `typescript-react` templates, you will automatically get a types definition file named `add-on-ui-sdk.d.ts` generated in your project `src` for you. This file contains the following exports, and allows you to take advantage of type checking and auto-completion features while developing with the Add-on SDK in your IDE.
```ts
@@ -136,7 +140,7 @@ The following properties can be accessed from the `addOnUISdk` object after it h
|
addOnUISdk.constants |
object |
- A set of constants used throughout the add-on SDK. |
+ A set of constants used throughout the add-on SDK. See the import patterns guide for proper usage. |
readonly |