Skip to content

Editor Mode

Editor mode provides the host application with a full geometry creation environment, with support for UI customization, slide management, undo/redo, and structured export.

Characteristics

  • Full-featured: Built-in complete dynamic geometry engine and toolbar.
  • Customizable UI: Hide specific panels to match your application layout.
  • Strict authorization: A valid appId must be provided during initialization.

Creating an Instance

typescript
import { createEditor, EmbeddedEditor } from '@dajiaoai/algeo-sdk';

const editor: EmbeddedEditor = await createEditor(container, {
  auth: { appId: 'YTVJDQZR' },
  ui: {
    navbar: false,
  },
});

See Getting Started for how to get an appId.

UI Configuration

Use ui to control visibility of editor panels.

PropertyTypeDefaultDescription
ui.navbarbooleantrueWhether to show the top navigation bar (including Save button and file info)
ui.slidePanelbooleantrueWhether to show the slide thumbnail panel
ui.toolboxPanelbooleantrueWhether to show the drawing toolbox
ui.algebraPanelbooleantrueWhether to show the algebra panel
ui.docPanelbooleantrueWhether to show the document panel
ui.helpEntrybooleantrueWhether to show the help entry in editor mode. Supported since 2.7.0.
ui.aiChatPanelbooleantrueWhether to show the AI Chat panel. Supported since 2.8.0.

API Module Reference

The SDK organizes the editor API into modules:

Create Options (AlgeoEditorCreateOptions)

typescript
interface AlgeoEditorCreateOptions {
  auth: {
    appId: string;
  };
  shareId?: string;
  initialContent?: FileContentLatest;
  ui?: AlgeoEditorUiConfig;
  fonts?: AlgeoFontConfig;
  resourceLibrary?: ResourceLibraryProvider;
}
OptionTypeRequiredDescription
auth.appIdstringyesOpen Platform application ID for editor-mode authorization
shareIdstringnoShared file ID to load during initialization
initialContentFileContentLatestnoFile content loaded after initialization
uiAlgeoEditorUiConfignoEditor UI visibility configuration
fontsAlgeoFontConfignoFont resources, picker catalog, and default font. Supported since 2.12.0.
resourceLibraryResourceLibraryProvidernoHost-provided read-only image library. Supported since 2.11.0.

See Custom Fonts for the type definitions, URL/base64 setup, and validation rules.

1. Document API (editor.document)

Handles overall content loading and retrieval.

  • loadContent(content: FileContentLatest): Promise<void>: Overwrite-load the current content.
  • getContent(): Promise<FileContentLatest>: Retrieve the complete DSL data from the current editor.
typescript
await editor.document.loadContent(content);
const content = await editor.document.getContent();

loadContent replaces the current project content and synchronizes editor state. getContent reads the latest content from the embedded editor and is useful as a final check before saving.

2. Slides API (editor.slides)

Manage multi-slide documents.

  • getCount(): number: Get the total slide count.
  • getCurrentIndex(): number: Get the current slide index.
  • switchTo(index: number): Promise<void>: Switch to the specified slide.
  • add(): Promise<SlideIndexResult>: Add a new slide at the end.
  • addAt(index: number): Promise<SlideIndexResult>: Insert a new slide at the specified position.
  • remove(index: number): Promise<void>: Delete the specified slide.
  • duplicate(index: number, targetIndex?: number): Promise<SlideIndexResult>: Duplicate the specified slide, optionally inserting it at a target position.
  • reorder(fromIndex: number, toIndex: number): Promise<void>: Reorder slides.
  • exportImage(options: ExportImageOptions): Promise<ExportedSlideImage[]>: Export slides as images.
  • exportLatex(options?: ExportLatexOptions): Promise<ExportedLatex[]>: Export LaTeX/TikZ source.
typescript
const total = editor.slides.getCount();
const current = editor.slides.getCurrentIndex();

await editor.slides.switchTo(1);
const added = await editor.slides.add();
const inserted = await editor.slides.addAt(0);
const duplicated = await editor.slides.duplicate(current, current + 1);

await editor.slides.reorder(0, 2);
await editor.slides.remove(1);
typescript
interface SlideIndexResult {
  index: number;
}

switchTo, remove, duplicate, and reorder use 0-based indices. The export APIs use 1-based slideIndices to match page-number semantics.

For a detailed comparison of all three image sizing modes, their parameters, and LaTeX export, see Export Images in Editor Mode.

3. History API (editor.history)

Control undo and redo.

  • getCount(): number: Get the history entry count.
  • getCurrentIndex(): number: Get the current history cursor.
  • undo(): Promise<void>: Undo.
  • redo(): Promise<void>: Redo.
  • jumpTo(index: number): Promise<void>: Jump to a specific history entry.
  • canUndo() / canRedo(): boolean: Check whether the respective operation is currently available.
  • clear(): Promise<void>: Clear history.
typescript
if (editor.history.canUndo()) {
  await editor.history.undo();
}

if (editor.history.canRedo()) {
  await editor.history.redo();
}

await editor.history.jumpTo(0);
await editor.history.clear();

4. Mode API (editor.mode)

Dynamically adjust the UI and master template style.

  • getUiConfig(): AlgeoEditorUiConfig: Get the SDK-side cached UI configuration.
  • setUiConfig(config: Partial<AlgeoEditorUiConfig>): Promise<void>: Dynamically toggle UI element visibility at runtime.
  • setMasterTemplate(template: string): Promise<SetMasterTemplateResult>: Set and persist the project's master template style. Supported since 2.9.0.
typescript
const ui = editor.mode.getUiConfig();

await editor.mode.setUiConfig({
  slidePanel: false,
  aiChatPanel: true,
});

await editor.mode.setMasterTemplate(masterTemplateContent);

You can download master template data that can be passed directly to setMasterTemplate from the Dino-GSP master template page.

5. AI API (editor.ai)

Supported since 2.8.0. See AI Chat in Editor for the full integration flow.

The AI API lets the host page pass the Dino-GSP backend stream, returned through the host backend, back to the embedded editor. It is usually used together with the aiRequest event.

  • setDraft(draft: AiDraftPayloadV1): Promise<void>: Set the AI Chat draft with text, images, openPanel, and focus. Supported since 2.9.0.
  • clearDraft(): Promise<void>: Clear the AI Chat draft text and images. Supported since 2.9.0.
  • consumeStream(input: { stream: ReadableStream<Uint8Array>; signal?: AbortSignal }): Promise<void>: Consume the streaming response returned by the Dino-GSP backend.
  • pushStreamEvent(event: AiStreamEventV1): void: Low-level event push API, mainly for SDK internals or integration debugging with the Dino-GSP backend. Normal integrations should prefer consumeStream.
typescript
await editor.ai.setDraft({
  text: 'Create a geometry problem based on this figure',
  images: ['https://example.com/figure.png'],
  openPanel: true,
  focus: true,
});

await editor.ai.clearDraft();

editor.on('aiRequest', async ({ payload, signal }) => {
  const response = await fetch('/api/ai/chat', {
    method: 'POST',
    body: JSON.stringify(payload),
    signal,
  });

  await editor.ai.consumeStream({
    stream: response.body!,
    signal,
  });
});

6. Image Library Protocol (resourceLibrary)

Supported since 2.11.0. See Insert Images from a Material Library for the full integration flow.

resourceLibrary is a Provider passed when creating the editor. When the user opens the image library, searches, or changes pages, the SDK calls the host's query implementation. The embedded editor then displays the returned images and inserts the selected image into the slide.

typescript
interface ResourceLibraryProvider {
  query(
    params: ResourceLibraryQuery,
    context: { signal: AbortSignal },
  ): Promise<ResourceLibraryResult>;
}
  • params.page starts at 1, and params.pageSize has a maximum value of 100.
  • params.keyword and params.mediaTypes are optional search filters.
  • context.signal cancels requests that are no longer needed. The host should pass it to asynchronous operations such as fetch.
  • Each returned item must have a unique id, a non-empty name, an image/* media type, and an absolute HTTP(S) image URL.
  • If resourceLibrary is not configured, the editor does not show the image library entry.

7. Lifecycle API

  • resize(): void: Supported since 2.10.0. Ask the embedded page to remeasure and redraw. The SDK calls it automatically when the container size changes; call it manually after other host layout changes.
  • destroy(): Promise<void>: Destroy the SDK instance, remove the iframe, clean up message listeners, and cancel pending requests.
typescript
editor.resize();
await editor.destroy();

Event Listening

Use editor.on(event, listener) to subscribe; it returns an unsubscribe function. You can also use editor.off(event, listener) to unsubscribe manually.

Supported events:

EventEvent dataDescription
ready{ type: 'ready', mode, version }iframe initialization complete
contentChange{ type: 'contentChange', source: 'user', content }Fires after the user edits inside the iframe; returns the full FileContentLatest
slideChange{ type: 'slideChange', index }Fires after the user switches slides inside the iframe; returns the current index
save{ type: 'save', stage: 'request' | 'success', content }stage: 'request': host handles persistence; stage: 'success': save flow is complete
aiRequest{ type: 'aiRequest', payload, signal }Embedded editor asks the host to run one AI request. Supported since 2.8.0.
aiCancel{ type: 'aiCancel', runId, reason }The active AI request was canceled. Supported since 2.8.0.

ready Event

Fires when the iframe finishes initialization. You can read the embedded page protocol version here.

typescript
editor.on('ready', (event) => {
  console.log('Editor ready, protocol version:', event.version);
});

contentChange Event

Fires after the user makes any modification to geometry figures or the slide structure inside the iframe. Returns the full FileContentLatest.

typescript
editor.on('contentChange', (event) => {
  // event.source is always 'user'
  console.log('Content updated:', event.content);
});

slideChange Event

Fires after the user switches slides inside the iframe. Returns the current slide index (0-based).

typescript
editor.on('slideChange', (event) => {
  console.log('Current slide index:', event.index);
});

save Event

The save event has two stages:

  1. request stage: Fires when the user clicks the save button. The host must complete persistence in the callback and return a result object. The iframe will only show a success state and proceed to the success stage after the host returns { status: 'success' }.
  2. success stage: Fires after the host confirms a successful save. At this point, event.content is the final saved content.
typescript
editor.on('save', async (event) => {
  if (event.stage === 'request') {
    const response = await fetch('/api/geometry-doc/save', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ content: event.content }),
    });

    if (!response.ok) {
      return { status: 'error', message: 'Save failed' };
    }

    return { status: 'success' };
  }

  // stage === 'success': iframe has shown success state
  console.log('Save confirmed, final content:', event.content);
});

Note: The request-stage listener must return a Promise (or be an async function), otherwise the iframe will not receive the host's handling result.


aiRequest Event

Fires when the user starts an AI conversation in the embedded editor. The host should send payload as-is to the host backend, let the host backend forward it to the Dino-GSP backend, and handle the returned stream through editor.ai.consumeStream().

typescript
editor.on('aiRequest', async ({ payload, signal }) => {
  const response = await fetch('/api/ai/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
    signal,
  });

  if (!response.ok || !response.body) {
    throw new Error('AI service request failed');
  }

  await editor.ai.consumeStream({
    stream: response.body,
    signal,
  });
});

payload is the AI request context generated by the editor. For normal integrations, forward it as-is. See AI Chat in Editor for the full flow.


aiCancel Event

Fires when the user cancels, a newer request supersedes the active request, or the SDK instance is destroyed.

typescript
editor.on('aiCancel', (event) => {
  console.log('AI request canceled:', event.runId, event.reason);
});

reason values:

ValueDescription
userThe user canceled the request
supersededA newer request replaced the active one
destroyedThe SDK instance was destroyed