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
appIdmust be provided during initialization.
Creating an Instance
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.
| Property | Type | Default | Description |
|---|---|---|---|
ui.navbar | boolean | true | Whether to show the top navigation bar (including Save button and file info) |
ui.slidePanel | boolean | true | Whether to show the slide thumbnail panel |
ui.toolboxPanel | boolean | true | Whether to show the drawing toolbox |
ui.algebraPanel | boolean | true | Whether to show the algebra panel |
ui.docPanel | boolean | true | Whether to show the document panel |
ui.helpEntry | boolean | true | Whether to show the help entry in editor mode. Supported since 2.7.0. |
ui.aiChatPanel | boolean | true | Whether 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)
interface AlgeoEditorCreateOptions {
auth: {
appId: string;
};
shareId?: string;
initialContent?: FileContentLatest;
ui?: AlgeoEditorUiConfig;
fonts?: AlgeoFontConfig;
resourceLibrary?: ResourceLibraryProvider;
}| Option | Type | Required | Description |
|---|---|---|---|
auth.appId | string | yes | Open Platform application ID for editor-mode authorization |
shareId | string | no | Shared file ID to load during initialization |
initialContent | FileContentLatest | no | File content loaded after initialization |
ui | AlgeoEditorUiConfig | no | Editor UI visibility configuration |
fonts | AlgeoFontConfig | no | Font resources, picker catalog, and default font. Supported since 2.12.0. |
resourceLibrary | ResourceLibraryProvider | no | Host-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.
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.
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);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.
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 since2.9.0.
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 withtext,images,openPanel, andfocus. Supported since2.9.0.clearDraft(): Promise<void>: Clear the AI Chat draft text and images. Supported since2.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 preferconsumeStream.
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.
interface ResourceLibraryProvider {
query(
params: ResourceLibraryQuery,
context: { signal: AbortSignal },
): Promise<ResourceLibraryResult>;
}params.pagestarts at1, andparams.pageSizehas a maximum value of100.params.keywordandparams.mediaTypesare optional search filters.context.signalcancels requests that are no longer needed. The host should pass it to asynchronous operations such asfetch.- Each returned item must have a unique
id, a non-emptyname, animage/*media type, and an absolute HTTP(S) image URL. - If
resourceLibraryis not configured, the editor does not show the image library entry.
7. Lifecycle API
resize(): void: Supported since2.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.
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:
| Event | Event data | Description |
|---|---|---|
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.
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.
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).
editor.on('slideChange', (event) => {
console.log('Current slide index:', event.index);
});save Event
The save event has two stages:
requeststage: 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 thesuccessstage after the host returns{ status: 'success' }.successstage: Fires after the host confirms a successful save. At this point,event.contentis the final saved content.
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 anasyncfunction), 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().
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.
editor.on('aiCancel', (event) => {
console.log('AI request canceled:', event.runId, event.reason);
});reason values:
| Value | Description |
|---|---|
user | The user canceled the request |
superseded | A newer request replaced the active one |
destroyed | The SDK instance was destroyed |