### Installation Guide Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/Release-notes.md Instructions on how to install the Obsidian Excalidraw plugin. Please back up your vault before proceeding with beta versions. ```APIDOC ## Installation **Note:** Install beta versions with caution as file formats may change. Back up your vault before installation. 1. Exit Obsidian. 2. Copy the files `main.js`, `manifest.json`, and `styles.css` to the `vault/.obsidian/plugins/obsidian-excalidraw-plugin/` folder. 3. Restart Obsidian. ``` -------------------------------- ### Initial Plugin Setup and Execution (JavaScript) Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Shade Master.md This snippet represents the initial setup and execution flow for the Excalidraw plugin. It involves storing original colors, displaying a modal, and starting the color processing queue. ```javascript await storeOriginalColors(); showModal(); processQueue(); ``` -------------------------------- ### Excalidraw Automate API Introduction Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/readme.md Provides an introduction to the Excalidraw Automate API, covering basic concepts and getting started. ```APIDOC ## Introduction to the API ### Description This section provides a foundational understanding of the Excalidraw Automate API, guiding users on how to begin using its features for programmatic control over Excalidraw drawings. ### Endpoint N/A (This is documentation, not a direct API endpoint) ### Parameters N/A ### Request Example N/A ### Response N/A ``` -------------------------------- ### Dataview: Family Tree Example Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/readme.md Example of creating a family tree visualization using DataviewJS and ExcalidrawAutomate. ```APIDOC ## Dataview: Family tree with Dataview ### Description This example shows how to build a family tree visualization in Excalidraw by fetching family data using DataviewJS and then rendering it with ExcalidrawAutomate. ### Method N/A (DataviewJS query) ### Endpoint N/A ### Parameters N/A ### Request Example ```javascript // DataviewJS query example for a family tree const ea = ExcalidrawAutomate; await ea.reset(); // Assume 'people' is a Dataview table with 'name' and 'parent' fields const people = await dv.pages('[tag:person]').sort(p => p.name); const personMap = {}; // Create nodes for (const person of people) { const nodeId = await ea.addText({ text: person.name }); personMap[person.name] = nodeId; } // Create connections for (const person of people) { if (person.parent && personMap[person.parent]) { await ea.connectObjects({ object1: personMap[person.parent], object2: personMap[person.name], arrows: { to: { type: "arrow", size: 10 } } }); } } ``` ### Response N/A ``` -------------------------------- ### Templater: Mindmap Example Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/readme.md A practical example of creating a mindmap using Templater and ExcalidrawAutomate. ```APIDOC ## Templater: Mindmap with Templater ### Description This example provides a script for Templater that generates a mindmap structure within Excalidraw, demonstrating the power of combining these tools. ### Method N/A (Templater script) ### Endpoint N/A ### Parameters N/A ### Request Example ```javascript // Templater script example for a simple mindmap const ea = ExcalidrawAutomate; await ea.reset(); const rootId = await ea.addText({ text: 'Root Node' }); const child1Id = await ea.addText({ text: 'Child 1', x: 100, y: 100 }); await ea.connectObjects({ object1: rootId, object2: child1Id }); ``` ### Response N/A ``` -------------------------------- ### Plugin Installation Files Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/Release-notes.md Lists the core files required to manually install the Obsidian Excalidraw plugin into the Obsidian vault. These files include the main JavaScript logic, the plugin manifest, and the stylesheet. ```plaintext main.js manifest.json style.css ``` -------------------------------- ### Generate Image from Text Prompt (OpenAI) Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/ExcaliAI.md Generates an image based on a detailed text prompt. OpenAI automatically enriches the prompt unless it starts with 'DO NOT add any detail, just use it AS-IS:'. Input is a text prompt. Output is an image. ```javascript let settings = ea.getScriptSettings(); const OPENAI_API_KEY = ea.plugin.settings.openAIAPIToken; if(!OPENAI_API_KEY || OPENAI_API_KEY === "") { new Notice("You must first configure your API key in Excalidraw Plugin Settings"); return; } let userPrompt = settings["User Prompt"] ?? ""; let agentTask = "Generate an image from prompt"; // Assumes systemPrompts object is defined elsewhere and contains the prompt for 'Generate an image from prompt' // Example structure: // const systemPrompts = { // "Generate an image from prompt": { // prompt: "Send only the text prompt to OpenAI. Provide a detailed description; OpenAI will enrich your prompt automatically. To avoid it, start your prompt like this 'DO NOT add any detail, just use it AS-IS:'", // type: "image-gen", // help: "Send only the text prompt to OpenAI. Provide a detailed description; OpenAI will enrich your prompt automatically. To avoid it, start your prompt like this 'DO NOT add any detail, just use it AS-IS:'" // }, // // ... other prompts // }; // The actual call to OpenAI API would be made here using OPENAI_API_KEY, userPrompt, and systemPrompts[agentTask].prompt ``` -------------------------------- ### Dataview: Mindmap Example Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/readme.md Example of generating a mindmap using DataviewJS and ExcalidrawAutomate. ```APIDOC ## Dataview: Mindmap with Dataview ### Description This example demonstrates how to dynamically generate a mindmap within an Excalidraw drawing by querying data using DataviewJS and manipulating it with ExcalidrawAutomate. ### Method N/A (DataviewJS query) ### Endpoint N/A ### Parameters N/A ### Request Example ```javascript // DataviewJS query example within an Excalidraw block const ea = ExcalidrawAutomate; await ea.reset(); const query = await dv.pages('"Mindmaps"').sort(t => t.file.name); let previousNodeId = null; for (let page of query) { const nodeId = await ea.addText({ text: page.file.name }); if (previousNodeId) { await ea.connectObjects({ object1: previousNodeId, object2: nodeId }); } previousNodeId = nodeId; } ``` ### Response N/A ``` -------------------------------- ### ExcalidrawAutomate Script Engine Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/readme.md Guide to using the ExcalidrawAutomate Script Engine for macro-like automation tasks. ```APIDOC ## ExcalidrawAutomate Script Engine ### Description The ExcalidrawAutomate Script Engine is recommended for automating simple, repetitive tasks within Excalidraw, such as modifying elements or setting canvas properties. This section provides details on how to use the engine. ### Endpoint N/A (This is documentation, not a direct API endpoint) ### Parameters N/A ### Request Example N/A ### Response N/A ``` -------------------------------- ### Install Obsidian Excalidraw Plugin Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/Release-notes.md Instructions for manually installing the Obsidian Excalidraw plugin. This involves copying specific files (main.js, manifest.json, styles.css) into the plugin directory within your Obsidian vault. Ensure Obsidian is closed before copying files and restarted afterward. ```plaintext Exit Obsidian. Copy the 3 files main.js, manifest.json, styles.css to the vault/.obsidian/plugins/obsidian-excalidraw-plugin/ folder. Restart Obsidian. ``` -------------------------------- ### Install Obsidian Excalidraw Plugin Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/Release-notes.md Instructions for installing the Excalidraw plugin for Obsidian. This involves copying specific files into the Obsidian plugins directory. Users are advised to back up their vault due to potential file format changes in beta versions. ```shell Exit Obsidian. Copy the 3 files `main.js`, `manifest.json`, `styles.css` to the `vault/.obsidian/plugins/obsidian-excalidraw-plugin/` folder. Restart Obsidian. ``` -------------------------------- ### Excalidraw File Create Hook Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/src/constants/assets/startupScript.md This callback is triggered when a new Excalidraw file is created. It allows for initial setup or default content generation for new drawings. It receives an object with the ExcalidrawAutomate instance, the Excalidraw file being created, and the view. ```javascript ea.onFileCreateHook = async (data) => { // data contains: // ea: ExcalidrawAutomate; // excalidrawFile: TFile; //the file being created // view: ExcalidrawView; }; ``` -------------------------------- ### Templater: Apply Excalidraw Template Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/readme.md Example of applying an Excalidraw template to a drawing using Templater. ```APIDOC ## Templater: Apply Excalidraw Template ### Description This example illustrates how to apply a pre-defined Excalidraw template to an existing or new drawing using the Templater plugin and ExcalidrawAutomate. ### Method N/A (Templater script) ### Endpoint N/A ### Parameters N/A ### Request Example ```javascript // Templater script example const ea = ExcalidrawAutomate; await ea.applyTemplate({ templatePath: "path/to/your/template.excalidraw" }); ``` ### Response N/A ``` -------------------------------- ### Templater: Connect Objects Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/readme.md Example demonstrating how to connect two objects in an Excalidraw drawing using Templater and ExcalidrawAutomate. ```APIDOC ## Templater: Connect Objects ### Description This example shows how to connect existing objects within an Excalidraw drawing using lines or arrows, leveraging the Templater plugin and ExcalidrawAutomate. ### Method N/A (Templater script) ### Endpoint N/A ### Parameters N/A ### Request Example ```javascript // Templater script example const ea = ExcalidrawAutomate; await ea.connectObjects({ object1: "id1", object2: "id2", stroke: "#ff0000", strokeWidth: 4 }); ``` ### Response N/A ``` -------------------------------- ### Inserting Obsidian Commands as Links in Excalidraw (Example) Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/Release-notes.md Demonstrates how to insert Obsidian commands as clickable links within Excalidraw. This allows for automation by triggering commands directly from Excalidraw elements, facilitating the creation of Excalidraw Scripts. ```markdown [[cmd://cmd-id]] ``` -------------------------------- ### Create DrawIO File with Excalidraw Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/index-new.md This script facilitates the creation of DrawIO diagram files within Obsidian. Upon execution, it prompts for a filename, generates the file, and opens it in the DrawIO plugin for immediate editing. It requires the 'Diagram plugin' to be installed. ```excalidraw-script-install https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Create%20DrawIO%20file.md ``` -------------------------------- ### API Key Configuration Check Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/ExcaliAI.md Checks if the OpenAI API key is configured in the Excalidraw plugin settings. If the key is missing or empty, it displays a notice to the user, preventing further AI operations until configured. This is a prerequisite for all AI features. ```javascript const OPENAI_API_KEY = ea.plugin.settings.openAIAPIToken; if(!OPENAI_API_KEY || OPENAI_API_KEY === "") { new Notice("You must first configure your API key in Excalidraw Plugin Settings"); return; } ``` -------------------------------- ### Install Excalidraw Script: Add Link to New Page and Open Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/index-new.md This script allows users to create and link to a new Markdown or Excalidraw document. It prompts for a filename and offers options to create the new file and open it in the current or an adjacent pane. A link is added to the selected Excalidraw elements. ```excalidraw-script-install https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Add%20Link%20to%20New%20Page%20and%20Open.md ``` -------------------------------- ### Example JSON for a Fine-Tipped Pen Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Archive/Alternative Pens.md An example configuration for a fine-tipped pen using JSON. This pen emphasizes constant pressure, a subtle smoothing, and a specific tapering for the start and end of lines. ```json { "constantPressure": true, "options": { "smoothing": 0.4, "thinning": -0.5, "streamline": 0.4, "easing": "linear", "start": { "taper": 5, "cap": false, }, "end": { "taper": 5, "cap": false, } } } ``` -------------------------------- ### Example JSON for a Thick Marker Pen Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Archive/Alternative Pens.md This JSON configuration defines a thick marker pen with a distinct outline. It uses constant pressure, significant thinning, and wide caps for both the start and end of lines. ```json { "constantPressure": true, "hasOutline": true, "outlineWidth": 4, "options": { "thinning": 1, "smoothing": 0.5, "streamline": 0.5, "easing": "linear", "start": { "taper": 0, "cap": true }, "end": { "taper": 0, "cap": true } } } ``` -------------------------------- ### Excalidraw Script Setup and Validation Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Shade Master.md This snippet sets up the Excalidraw plugin script, including defining help text, verifying the minimum plugin version, and handling initial script settings. It ensures the Excalidraw plugin version is compatible and sets default values for color modification settings if they don't exist. ```javascript const HELP_TEXT = ` - Select SVG images, nested Excalidraw drawings and/or regular Excalidraw elements - For a single selected image, you can map colors individually in the color mapping section - For Excalidraw elements: stroke and background colors are modified permanently - For SVG/nested drawings: original files stay unchanged, color mapping is stored under \`## Embedded Files\` - Using color maps helps maintain links between drawings while allowing different color themes - Sliders work on relative scale - the amount of change is applied to current values - Unlike Excalidraw's opacity setting which affects the whole element: - Shade Master can set different opacity for stroke vs background - **Note:** SVG/nested drawing colors are mapped at color name level, thus \"black\" is different from \"#000000\" - Additionally if the same color is used as fill and stroke the color can only be mapped once - This is an experimental script - contributions welcome on GitHub via PRs ![](https://www.youtube.com/embed/ISuORbVKyhQ) `; if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("2.7.2")) { new Notice("This script requires a newer version of Excalidraw. Please install the latest version."); return; } /* SVGColorInfo is returned by ea.getSVGColorInfoForImgElement. Color info will all the color strings in the SVG file plus "fill" which represents the default fill color for SVG icons set at the SVG root element level. Fill if not set defaults to black: type SVGColorInfo = Map; In the Excalidraw file under `## Embedded Files` the color map is included after the file. That color map implements ColorMap. ea.updateViewSVGImageColorMap takes a ColorMap as input. interface ColorMap { [color: string]: string; }; */ // Main script execution const allElements = ea.getViewSelectedElements(); const svgImageElements = allElements.filter(el => { if(el.type !== "image") return false; const file = ea.getViewFileForImageElement(el); if(!file) return false; return el.type === "image" && ( file.extension === "svg" || ea.isExcalidrawFile(file) ); }); if(allElements.length === 0) { new Notice("Select at least one rectangle, ellipse, diamond, line, arrow, freedraw, text or SVG image elment"); return; } const originalColors = new Map(); const currentColors = new Map(); const colorInputs = new Map(); const sliderResetters = []; let terminate = false; const FORMAT = "Color Format"; const STROKE = "Modify Stroke Color"; const BACKGROUND = "Modify Background Color" const ACTIONS = ["Hue", "Lightness", "Saturation", "Transparency"]; const precision = [1,2,2,3]; const minLigtness = 1/Math.pow(10,precision[2]); const maxLightness = 100 - minLigtness; const minSaturation = 1/Math.pow(10,precision[2]); let settings = ea.getScriptSettings(); //set default values on first run if(!settings[STROKE]) { settings = {}; settings[FORMAT] = { value: "HEX", valueset: ["HSL", "RGB", "HEX"], description: "Output color format." }; settings[STROKE] = { value: true } settings[BACKGROUND] = {value: true } ea.setScriptSettings(settings); } function getRegularElements() { ea.clear(); //loading view elements again as element objects change when colors are updated const allElements = ea.getViewSelectedElements(); return allElements.filter(el => ["rectangle", "ellipse", "diamond", "line", "arrow", "freedraw", "text"].includes(el.type) ); } const updatedImageElementColorMaps = new Map(); let isWaitingForSVGUpdate = false; function updateViewImageColors() { if(terminate || isWaitingForSVGUpdate || updatedImageElementColorMaps.size === 0) { return; } isWaitingForSVGUpdate = true; elementArray = Array.from(updatedImageElementColorMaps.keys()); colorMapArray = Array.from(updatedImageElementColorMaps.values()); updatedImageElementColorMaps.clear(); ``` -------------------------------- ### create() - Create and open a new drawing Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/AutomateHowTo.md Creates a new Excalidraw drawing with specified parameters and opens it. You can define the filename, folder, use a template, and choose whether to open in a new pane. ```APIDOC ## POST /create ### Description Creates the drawing and opens it. Allows specifying filename, folder, template, and opening behavior. ### Method POST ### Endpoint /create ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **params** ({filename: string, foldername:string, templatePath:string, onNewPane: boolean}) - Optional - Parameters for creating the drawing. - **filename** (string) - Optional - The filename without extension. If null, Excalidraw generates one. - **foldername** (string) - Optional - The folder to create the file in. If null, uses default Excalidraw settings. - **templatePath** (string) - Optional - Full path and extension for a template file. If null, uses an empty drawing. - **onNewPane** (boolean) - Optional - Defines where the drawing should be created. `false` opens in the current active leaf, `true` splits the current leaf vertically. ### Request Example ```json { "params": { "filename": "my drawing", "foldername": "myfolder/subfolder/", "templatePath": "Excalidraw/template.excalidraw", "onNewPane": true } } ``` ### Response #### Success Response (200) - **void** - This function does not return a value. ``` -------------------------------- ### Get Template File Path from Settings Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Image Occlusion.md This asynchronous JavaScript function retrieves the default template file path from Obsidian's settings. It is intended to be used in conjunction with a Templater plugin setup to specify which template to use for creating new markdown files. ```javascript // Function to get template file based on settings const getTemplateFile = async (templates) => { // Get default template path from settings ``` -------------------------------- ### Initialize Excalidraw Automate Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/API/introduction.md This snippet shows the basic initialization of the Excalidraw Automate object. It's recommended to start Templater, DataView, and QuickAdd scripts with this code. The `reset()` function ensures a clean state for Excalidraw Automate before executing new commands. ```javascript const ea = ExcalidrawAutomate; ea.reset(); ``` -------------------------------- ### Excalidraw Plugin Script Initialization and Settings Loading Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Palette loader.md This script snippet handles the initialization of the Excalidraw plugin and loads user-defined settings. It verifies the minimum plugin version required and retrieves script settings, setting default values if none are found. It also defines constants for color grays and the palette folder path. ```javascript //-------------------------- // Load settings //-------------------------- if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.9.2")) { new Notice("This script requires a newer version of Excalidraw. Please install the latest version."); return; } const api = ea.getExcalidrawAPI(); let settings = ea.getScriptSettings(); //set default values on first run if(!settings["Palette folder"]) { settings = { "Palette folder" : { value: "Excalidraw/Palettes", description: "The path to the folder where you store the Excalidraw Palettes" }, "Light-gray" : { value: "#505050", description: "Base light-gray used for mixing with the accent color to generate the palette light-gray" }, "Dark-gray" : { value: "#e0e0e0", description: "Base dark-gray used for mixing with the accent color to generate the palette dark-gray" } }; ea.setScriptSettings(settings); } const lightGray = settings["Light-gray"].value; const darkGray = settings["Dark-gray"].value; let paletteFolder = settings["Palette folder"].value.toLowerCase(); if(paletteFolder === "" || paletteFolder === "/") { new Notice("The palette folder cannot be the root folder of your vault"); return; } if(!paletteFolder.endsWith("/")) paletteFolder += "/"; ``` -------------------------------- ### Markdown Transclusion Example Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/Release-notes.md Illustrates how subsections of a document are expected to be transcluded in markdown. This example clarifies a bug fix where transclusions incorrectly omitted subsections. ```markdown # A abc # B xyz ## b1 123 ## b2 456 # C When you transclude `![[document#B]]` you expect the following result ``` B xyz b1 123 b2 456 ``` Until this fix you only got ``` B xyz ``` ``` -------------------------------- ### Excalidraw Slideshow Script Introduction (Markdown) Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/Release-notes.md Announces the availability of the Excalidraw Slideshow Script, accessible via the script store. This script enables the creation of presentations directly within Excalidraw. ```markdown [Excalidraw Slideshow Script](https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Slideshow.md) ``` -------------------------------- ### Get Multiple Selected Elements in Excalidraw View Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/API/utility.md Retrieves an array of all selected Excalidraw elements in the scene. Requires setting the view with `setView()`. Returns an empty array if no elements are selected. Use `getExcalidrawAPI().getSceneElements()` to get all elements. ```typescript getViewSelectedElements():ExcalidrawElement[] ``` -------------------------------- ### Create Initial Frame Settings UI - JavaScript Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Printable Layout Wizard.md Generates the initial UI for frame creation when no frames exist yet. This includes input fields for page size and orientation, styled using CSS Grid for a multi-column layout. It also initializes a dropdown for page size selection. ```javascript // When no frames yet: initial size/orientation inputs and Create First Frame button if (!hasFrames) { const settingsContainer = framesTabEl.createDiv({ attr: { // four columns: label + input, label + input style: "display: grid; grid-template-columns: auto 1fr auto 1fr; gap: 10px; align-items: center;" } }); // Page Size settingsContainer.createEl("label", { text: "Page Size:" }); const pageSizeDropdown = settingsContainer.createEl("select", { cls: "dropdown", attr: { style: "width: 100%;" } }); ``` -------------------------------- ### Recalculate Start Point of Line for Excalidraw Arrows Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Auto Layout.md Recalculates the start point of a line (arrow) to connect accurately to its bound element. It determines the intersection point between the element and the line, adjusting the line's points and position accordingly. ```javascript function recalculateStartPointOfLine(line, el, elB, gapValue) { const aX = el.x + el.width / 2; const bX = line.points.length <= 2 && elB ? elB.x + elB.width / 2 : line.x + line.points[1][0]; const aY = el.y + el.height / 2; const bY = line.points.length <= 2 && elB ? elB.y + elB.height / 2 : line.y + line.points[1][1]; line.startBinding.gap = gapValue; line.startBinding.focus = 0; const intersectA = ea.intersectElementWithLine( el, [bX, bY], [aX, aY], line.startBinding.gap ); if (intersectA.length > 0) { line.points[0] = [0, 0]; for (let i = 1; i < line.points.length; i++) { line.points[i][0] -= intersectA[0][0] - line.x; line.points[i][1] -= intersectA[0][1] - line.y; } line.x = intersectA[0][0]; line.y = intersectA[0][1]; } } ``` -------------------------------- ### Excalidraw Plugin System Prompts for AI Interactions Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/ExcaliAI.md This JavaScript snippet defines 'systemPrompts', an object containing predefined prompts for AI interactions within the Excalidraw plugin. Each prompt includes instructions for the AI, the expected output type, and a user-facing help message, facilitating various AI-powered features like diagram generation and image editing. ```javascript const systemPrompts = { "Challenge my thinking": { prompt: `Your task is to interpret a screenshot of a whiteboard, translating its ideas into a Mermaid graph. The whiteboard will encompass thoughts on a subject. Within the mind map, distinguish ideas that challenge, dispute, or contradict the whiteboard content. Additionally, include concepts that expand, complement, or advance the user's thinking. Utilize the Mermaid graph diagram type and present the resulting Mermaid diagram within a code block. Ensure the Mermaid script excludes the use of parentheses ().`, type: "mermaid", help: "Translate your image and optional text prompt into a Mermaid mindmap. If there are conversion errors, edit the Mermaid script under 'More Tools'." }, "Convert sketch to shapes": { prompt: `Given an image featuring various geometric shapes drawn by the user, your objective is to analyze the input and generate SVG code that accurately represents these shapes. Your output will be the SVG code enclosed in an HTML code block.`, type: "svg", help: "Convert selected scribbles into shapes; works better with fewer shapes. Experimental and may not produce good drawings." }, "Create a simple Excalidraw icon": { prompt: `Given a description of an SVG image from the user, your objective is to generate the corresponding SVG code. Avoid incorporating textual elements within the generated SVG. Your output should be the resulting SVG code enclosed in an HTML code block.`, type: "svg", help: "Convert text prompts into simple icons inserted as Excalidraw elements. Expect only a text prompt. Experimental and may not produce good drawings." }, "Create a stick figure": { prompt: "You will receive a prompt from the user. Your task involves drawing a simple stick figure or a scene involving a few stick figures based on the user's prompt. Create the stickfigure based on the following style description. DO NOT add any detail, just use it AS-IS: Create a simple stick figure character with a large round head and a face in the style of sketchy caricatures. The stick figure should have a rudimentary body composed of straight lines representing the arms and legs. Hands and toes should be should be represented with round shapes, do not add details such as fingers or toes. Use fine lines, smooth curves, rounded shapes. The stick figure should retain a playful and childlike simplicity, reminiscent of a doodle someone might draw on the corner of a notebook page. Create a black and white drawing, a hand-drawn figure on white background.", type: "image-gen", help: "Send only the text prompt to OpenAI. Provide a detailed description; OpenAI will enrich your prompt automatically. To avoid it, start your prompt like this 'DO NOT add any detail, just use it AS-IS:'" }, "Edit an image": { prompt: null, type: "image-edit", help: "Image elements will be used as the Image. Shapes on top of the image will be the Mask. Use the prompt to instruct Dall-e about the changes. Dall-e-2 model will be used." }, "Generate an image from image and prompt": { prompt: "Your task involves receiving an image and a textual prompt from the user. Your goal is to craft a detailed, accurate, and descriptive narrative of the image, tailored for effective image generation. Utilize the user-provided text prompt to inform and guide your depiction of the image. Ensure the resulting image remains text-free.", type: "image-gen" } } ``` -------------------------------- ### Configure Obsidian Modal for Excalidraw Plugin Settings Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/ExcaliAI.md This code configures a modal window in Obsidian for the Excalidraw plugin. It sets the modal's width, defines its `onOpen` and `onClose` event handlers, and dynamically creates UI elements such as headings, text areas for prompts, dropdowns for task selection, and buttons. The `onOpen` function initializes the modal's content, including settings for system prompts, user prompts, and image size, and handles logic for updating the UI based on the selected task type. ```javascript const configModal = new ea.obsidian.Modal(app); configModal.modalEl.style.width="100%"; configModal.modalEl.style.maxWidth="1000px"; configModal.onOpen = async () => { const contentEl = configModal.contentEl; contentEl.createEl("h1", {text: "ExcaliAI"}); let systemPromptTextArea, systemPromptDiv, imageSizeSetting, imageSizeSettingDropdown, helpEl; new ea.obsidian.Setting(contentEl) .setName("What would you like to do?") .addDropdown(dropdown=>{ Object.keys(systemPrompts).forEach(key=>dropdown.addOption(key,key)); dropdown .setValue(agentTask) .onChange(async (value) => { dirty = true; const prevTask = agentTask; agentTask = value; if( (systemPrompts[prevTask].type === "image-edit" && systemPrompts[value].type !== "image-edit") || (systemPrompts[prevTask].type !== "image-edit" && systemPrompts[value].type === "image-edit") ) { ({imageDataURL, maskDataURL} = await generateCanvasDataURL(ea.targetView, systemPrompts[value].type === "image-edit")); addPreviewImage(); setImageModelAndSizes(); while (imageSizeSettingDropdown.selectEl.options.length > 0) { imageSizeSettingDropdown.selectEl.remove(0); } validSizes.forEach(size=>imageSizeSettingDropdown.addOption(size,size)); imageSizeSettingDropdown.setValue(imageSize); } imageSizeSetting.settingEl.style.display = isImageGenerationTask() ? "" : "none"; const prompt = systemPrompts[value].prompt; helpEl.innerHTML = `Help: ` + systemPrompts[value].help; if(prompt) { systemPromptDiv.style.display = ""; systemPromptTextArea.setValue(systemPrompts[value].prompt); } else { systemPromptDiv.style.display = "none"; } }); }) helpEl = contentEl.createEl("p"); helpEl.innerHTML = `Help: ` + systemPrompts[agentTask].help; systemPromptDiv = contentEl.createDiv(); systemPromptDiv.createEl("h4", {text: "Customize System Prompt"}); systemPromptDiv.createEl("span", {text: "Unless you know what you are doing I do not recommend changing the system prompt"}) const systemPromptSetting = new ea.obsidian.Setting(systemPromptDiv) .addTextArea(text => { systemPromptTextArea = text; const prompt = systemPrompts[agentTask].prompt; text.inputEl.style.minHeight = "10em"; text.inputEl.style.width = "100%"; text.setValue(prompt); text.onChange(value => { systemPrompts[value].prompt = value; }); if(!prompt) systemPromptDiv.style.display = "none"; }) systemPromptSetting.nameEl.style.display = "none"; systemPromptSetting.descEl.style.display = "none"; systemPromptSetting.infoEl.style.display = "none"; contentEl.createEl("h4", {text: "User Prompt"}); const userPromptSetting = new ea.obsidian.Setting(contentEl) .addTextArea(text => { text.inputEl.style.minHeight = "10em"; text.inputEl.style.width = "100%"; text.setValue(userPrompt); text.onChange(value => { userPrompt = value; dirty = true; }) }) userPromptSetting.nameEl.style.display = "none"; userPromptSetting.descEl.style.display = "none"; userPromptSetting.infoEl.style.display = "none"; imageSizeSetting = new ea.obsidian.Setting(contentEl) .setName("Select image size") .setDesc(fragWithHTML("⚠️ Important ⚠️: " + IMAGE_WARNING)) .addDropdown(dropdown=>{ validSizes.forEach(size=>dropdown.addOption(size,size)); imageSizeSettingDropdown = dropdown; dropdown .setValue(imageSize) .onChange(async (value) => { dirty = true; imageSize = value; if(systemPrompts[agentTask].type === "image-edit") { ({imageDataURL, maskDataURL} = await generateCanvasDataURL(ea.targetView, true)); addPreviewImage(); } }); }) imageSizeSetting.settingEl.style.display = isImageGenerationTask() ? "" : "none"; if(imageDataURL) { previewDiv = contentEl.createDiv({ attr: { style: "text-align: center;", } }); addPreviewImage(); } else { contentEl.createEl("h4", {text: "No elements are selected from your canvas"}); contentEl.createEl("span", {text: "Because there are no Excalidraw elements selected on the canvas, only the text prompt will be sent to OpenAI."}); } new ea.obsidian.Setting(contentEl) .addButton(button => button .setButtonText("Run") .onClick((event)=>{ run(userPrompt); //Obsidian crashes otherwise, likely has to do with requesting an new frame for react configModal.close(); }) ); } configModal.onClose = () => { if(dirty) { ``` -------------------------------- ### Install Excalidraw Script: Add Connector Point Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/index-new.md This script adds a connector point (a small circle) to the top-left of selected text elements, grouping them with the connector. This is useful for linking text elements with arrows, particularly in Wardley Maps. The installation command is provided. ```excalidraw-script-install https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Add%20Connector%20Point.md ``` -------------------------------- ### ExcalidrawAutomate Help Functionality Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/Release-notes.md The ExcalidrawAutomate library now includes a `help()` function to provide documentation for its functions and properties directly from the Developer Console. This aids developers in understanding and utilizing the library's capabilities. ```javascript ea.help() You can use this function from Developer Console to print help information about functions. Usage: ea.help(ea.functionName) or ea.help('propertyName') - notice property name is in quotes ``` -------------------------------- ### Analyze Obsidian Excalidraw Plugin Startup Time Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/Release-notes.md This command helps diagnose startup performance issues within the Excalidraw plugin for Obsidian. Open the developer console and execute this command to get a breakdown of startup times. It requires no specific inputs but provides a detailed output. ```javascript ExcalidrawAutomate.printStartupBreakdown() ``` -------------------------------- ### Recalculate Line Start Point Intersection - JavaScript Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Box Each Selected Groups.md Calculates and adjusts the starting point of a line to intersect with a given element. It determines intersection points and modifies the line's coordinates and points array accordingly. Utilizes the 'ea.intersectElementWithLine' function. ```javascript function recalculateStartPointOfLine(line, el) { const aX = el.x + el.width/2; const bX = line.x + line.points[1][0]; const aY = el.y + el.height/2; const bY = line.y + line.points[1][1]; line.startBinding.gap = 8; line.startBinding.focus = 0; const intersectA = ea.intersectElementWithLine( el, [bX, bY], [aX, aY], line.startBinding.gap ); if(intersectA.length > 0) { line.points[0] = [0, 0]; for(var i = 1; i { const tmpShouldClose = shouldClose; shouldClose = true; await createFirstFrame(pageSizeDropdown.value, orientationDropdown.value); shouldClose = tmpShouldClose; if(!shouldClose) { shouldRestart = true; modal.close() } }); ``` -------------------------------- ### Excalidraw Script Settings and Initialization (JavaScript) Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Excalidraw Writing Machine.md This JavaScript code snippet initializes settings for the Excalidraw Writing Machine script. It loads existing settings or sets default values for template path, ZK summary/source sections, and image embedding preferences. It also handles updating the settings if changes are detected. ```javascript const selectedElements = ea.getViewSelectedElements(); if (selectedElements.length !== 1 || selectedElements[0].type === "arrow") { new Notice("Select a single element that is not an arrow and not a frame"); return; } const visited = new Set(); // Avoiding recursive infinite loops delete window.ewm; await ea.targetView.save(); //------------------ // Load Settings //------------------ let settings = ea.getScriptSettings(); //set default values on first run let didSettingsChange = false; if(!settings["Template path"]) { settings = { "Template path" : { value: "", description: "The template file path that will receive the concatenated text. If the file includes <<>> then it will be replaced with the generated text, if <<>> is not present in the file the hierarchical markdown generated from the diagram will be added to the end of the template." }, "ZK '# Summary' section": { value: "Summary", description: "The section in your visual zettelkasten file that contains the short written summary of the idea. This is the text that will be included in the hierarchical markdown file if visual ZK cards are included in your flow" }, "ZK '# Source' section": { value: "Source", description: "The section in your visual zettelkasten file that contains the reference to your source. If present in the file, this text will be included in the output file as a reference" }, "Embed image links": { value: true, description: "Should the resulting markdown document include the ![[embedded images]]?" } }; didSettingsChange = true; } if(!settings["Generate ![markdown](links)"]) { settings["Generate ![markdown](links)"] = { value: true, description: "If you turn this off the script will generate ![[wikilinks]] for images" } didSettingsChange = true; } if(didSettingsChange) { await ea.setScriptSettings(settings); } const ZK_SOURCE = settings["ZK '# Source' section"].value; const ZK_SECTION = settings["ZK '# Summary' section"].value; const INCLUDE_IMG_LINK = settings["Embed image links"].value; const MARKDOWN_LINKS = settings["Generate ![markdown](links)"].value; let templatePath = settings["Template path"].value; //------------------ // Select template file //------------------ const MSG = "Select another file" let selection = MSG; if(templatePath && app.vault.getAbstractFileByPath(templatePath)) { selection = await utils.suggester([templatePath, MSG],[templatePath, MSG], "Use previous template or select another?"); if(!selection) { new Notice("process aborted"); return; } } if(selection === MSG) { const files = app.vault.getMarkdownFiles().map(f=>f.path); selection = await utils.suggester(files,files,"Select the template to use. ESC to not use a tempalte"); } if(selection && selection !== templatePath) { settings["Template path"].value = selection; await ea.setScriptSettings(settings); } templatePath = selection; ``` -------------------------------- ### Templater: Insert New Drawing Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/readme.md Example of how to use Templater to insert a new Excalidraw drawing into the currently edited document. ```APIDOC ## Templater: Insert New Drawing ### Description This example demonstrates how to create and insert a new Excalidraw drawing into your Obsidian note using the Templater plugin and ExcalidrawAutomate. ### Method N/A (Templater script) ### Endpoint N/A ### Parameters N/A ### Request Example ```javascript // Templater script example const ea = ExcalidrawAutomate; await ea.reset(); await ea.newExcalidraw({ main:“new drawing” }); ``` ### Response N/A ``` -------------------------------- ### Get Excalidraw View Elements Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/API/attributes_functions_overview.md Retrieves all Excalidraw elements currently present in the target view. ```typescript getViewElements(): ExcalidrawElement[]; ``` -------------------------------- ### Create Simple Drawing with Templater Source: https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/docs/API/introduction.md This Templater script demonstrates how to create a simple Excalidraw drawing by adding basic shapes and text. It showcases setting stroke color and adding text with specific alignment and width. The `ea.create()` function is used to render the drawing. ```javascript <%* const ea = ExcalidrawAutomate; ea.reset(); ea.addRect(-150,-50,450,300); ea.addText(-100,70,"Left to right"); ea.addArrow([[-100,100],[100,100]]); ea.style.strokeColor = "red"; ea.addText(100,-30,"top to bottom",{width:200,textAligh:"center"}); ea.addArrow([[200,0],[200,200]]); await ea.create(); %> ```