Get AI summaries of any video or article — Sign up free
Excalidraw Script Engine Coding Example: Building a Gallery View thumbnail

Excalidraw Script Engine Coding Example: Building a Gallery View

5 min read

Based on Zsolt's Visual Personal Knowledge Management's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.

TL;DR

The script builds a thumbnail list by filtering `app.vault.getMarkdownFiles()` using both folder-path matching and a case-insensitive `thumbnail` substring on the base filename.

Briefing

A working Excalidraw automation script can turn an Obsidian vault of YouTube thumbnails (and optional storyboard notes) into a clickable, grid-style “gallery view” on an Excalidraw canvas—without manually dragging images one by one. The core payoff is speed plus structure: the script scans the vault for thumbnail files, sorts them by creation time, pairs each thumbnail with its matching storyboard markdown (when present), then lays everything out in a 12-column matrix with consistent spacing and aspect-ratio-friendly sizing.

The workflow starts by creating an empty Excalidraw drawing and attaching Excalidraw Automate to the active window via the developer console. From there, the script derives the target folder path from the current file’s path and name, then builds a list of candidate thumbnail markdown files. It filters by two conditions: the file path must start with the computed folder path, and the file base name (lowercased for casing tolerance) must contain the word “thumbnail.” In the author’s vault, this yields 145 thumbnail-related markdown files.

Sorting matters because thumbnails need to appear in chronological order rather than arbitrary filesystem order. The script uses each file’s `stat.ctime` (creation time) and converts it into a Moment-formatted date string for comparison. After an initial reversal mistake, the sort logic is flipped so the oldest items come first—confirmed by checking the first element corresponds to an older video date.

Next comes the pairing step: for each thumbnail file, the script searches for a corresponding storyboard markdown file in the same folder. It does this by reusing the folder path and filtering for markdown files whose base name matches “storyboard.” If a storyboard exists, the script grabs the first match; if not, it keeps the storyboard value undefined using a safe optional approach.

The layout step is where the script becomes practical. It defines a grid placement function that computes row and column coordinates using modulo arithmetic (the grid uses 12 columns). Each thumbnail is added to Excalidraw with `EA add image`, then the image element is updated so its link becomes a markdown link to the storyboard file path—making each thumbnail clickable and navigable to the storyboard.

Asynchronous image loading introduces real-world friction. An initial attempt using a bulk “add elements” approach starts loading images in the background and can lead to timing issues, distorted sizing, and confusing console behavior. The final, reliable version switches to a sequential `for` loop that awaits each image load before placing the next one. That change prevents race conditions and results in a clean matrix where all images appear and links work.

By the end, the canvas contains the full gallery of thumbnails arranged in rows and columns, with storyboard links attached per image. The author’s takeaway is that Excalidraw Automate can be used to automate repeatable knowledge-management workflows inside Obsidian—turning a messy manual process into a deterministic script-driven layout.

Cornell Notes

The script automates a “gallery view” in Excalidraw by scanning an Obsidian vault for thumbnail markdown files, sorting them by creation time, and pairing each thumbnail with an optional matching storyboard markdown file. It computes a 12-column grid layout using modulo arithmetic and places each thumbnail image onto the Excalidraw canvas with calculated x/y coordinates, spacing, and dimensions. Each image is then updated so it links to the storyboard file path, making the gallery clickable. A key reliability fix is switching from bulk asynchronous placement to a sequential `for` loop that awaits image loading, avoiding race conditions and distorted output. This matters because it replaces manual drag-and-drop with a repeatable, vault-driven workflow.

How does the script identify which files count as thumbnails in the vault?

It derives a folder path from the current target view’s `F path` and `F name` by splitting the path at the filename boundary. Then it calls `app.vault.getMarkdownFiles()` and filters for files where `F path` starts with that folder path and where the lowercased base name contains the substring `thumbnail`. This yields a concrete list (145 files in the author’s vault) to feed into sorting and layout.

What determines the ordering of thumbnails on the Excalidraw canvas?

Ordering comes from each file’s `stat.ctime` (creation time). The script compares `F1.stat.ctime` and `F2.stat.ctime` inside a custom sort comparator. It uses Moment formatting to make the date comparisons meaningful, then corrects the comparator direction so the oldest items appear first (the first element is verified as an older video date, not the newest).

How does the script attach storyboard links to each thumbnail?

For each thumbnail, it searches within the same folder for a markdown file whose base name matches `storyboard`. It uses `app.vault.getMarkdownFiles()` plus a filter on `F path` starting with the folder path and then selects the first matching storyboard file (or leaves it undefined if none exists). When placing the image, it sets the image element’s link to a markdown link built from the storyboard file’s `path` (guarded with optional handling like `storyboard?.path`).

Why did the initial image placement attempt produce timing and sizing problems?

The first approach relied on asynchronous image loading while adding elements in a way that didn’t guarantee each image was ready before placement. That can cause overlapping/timing issues and makes it harder to update the image link reliably. It also produced distorted sizing when the chosen width/height math didn’t match actual scaling behavior. The fix was to clear the canvas and rerun with a sequential `for` loop that awaits each image load before adding the next element.

How does the grid layout math work (rows/columns)?

The script uses a 12-column grid. For each thumbnail index, it computes `row` using modulo arithmetic (e.g., `index % 12`), and it advances columns when `row == 0`. It then calculates x/y coordinates using `column * padding + column * width` for x and `row * padding + row * height` for y, producing a consistent matrix layout across the canvas.

Review Questions

  1. What two filter conditions does the script use to build the thumbnail list from `getMarkdownFiles()`?
  2. How does the script use `stat.ctime` (and Moment) to sort thumbnails into chronological order?
  3. What change made the final image placement reliable: bulk async placement or sequential `for` loop with awaiting image loads? Explain why.

Key Points

  1. 1

    The script builds a thumbnail list by filtering `app.vault.getMarkdownFiles()` using both folder-path matching and a case-insensitive `thumbnail` substring on the base filename.

  2. 2

    Chronological ordering is achieved by sorting on each file’s `stat.ctime`, with Moment formatting used to interpret dates and a corrected comparator direction to show oldest-first.

  3. 3

    Each thumbnail is paired with an optional storyboard markdown file by searching the same folder for a base name of `storyboard` and selecting the first match when present.

  4. 4

    A 12-column grid layout is computed from the thumbnail index using modulo arithmetic, then translated into x/y coordinates with padding plus width/height terms.

  5. 5

    Clickable behavior comes from updating each Excalidraw image element’s link to a markdown link pointing to the storyboard file path.

  6. 6

    Reliability improves when image placement is done sequentially with a `for` loop that awaits image loading, avoiding race conditions seen in earlier bulk/asynchronous attempts.

Highlights

A vault-driven Excalidraw gallery can be generated automatically by scanning for thumbnail markdown files and laying them out in a grid.
Sorting by `stat.ctime` (with Moment formatting) turns an unordered vault into a meaningful chronological gallery.
Clickable thumbnails are created by linking each Excalidraw image element to the matching storyboard markdown file path.
Switching from bulk async placement to a sequential `for` loop prevents race conditions and produces a clean, complete grid.

Topics

  • Excalidraw Automate
  • Obsidian Vault Scripting
  • Gallery Grid Layout
  • File Filtering
  • Async Image Loading

Mentioned

  • EA