name: logseq-whiteboards description: Create and edit LogSeq Whiteboard files (.edn) with shapes, connectors, portals, and embeds on an infinite canvas. Use when working with whiteboard .edn files in a LogSeq graph, creating visual diagrams, mind maps, or spatial canvases, or when the user mentions LogSeq whiteboards.
LogSeq Whiteboards
LogSeq Whiteboards are infinite spatial canvases stored as .edn (Extensible Data Notation) files. Built on a custom fork of tldraw, they combine freeform drawing with LogSeq's knowledge graph — allowing you to place pages, blocks, shapes, connectors, images, and web embeds together on a visual canvas.
File Location
Whiteboard files are stored in the whiteboards/ directory of a LogSeq graph:
my-graph/
├── journals/
├── pages/
├── whiteboards/ ← Whiteboard .edn files here
│ ├── My Diagram.edn
│ └── Project Board.edn
├── assets/ ← Images referenced by whiteboards
└── logseq/
└── config.edn ← Can customize :whiteboards-directory
The directory name can be changed in config.edn via :whiteboards-directory.
EDN File Structure
Every whiteboard .edn file has two top-level sections: :blocks (shapes) and :pages (canvas metadata).
{:blocks (
;; Each shape is a block with :logseq.tldraw.shape properties
{:block/created-at 1728698317371
:block/properties
{:ls-type :whiteboard-shape
:logseq.tldraw.shape
{:type "text"
:id "unique-uuid"
:point [100 200]
:size [300 50]
;; ... shape-specific properties
}}
:block/updated-at 1728698317371}
;; More shape blocks...
)
:pages (
;; One page entry per whiteboard
{:block/uuid #uuid "page-uuid-here"
:block/properties
{:ls-type :whiteboard-page
:logseq.tldraw.page
{:id "page-uuid-here"
:name "whiteboard-name"
:bindings {}
:nonce 1
:assets []
:shapes-index ("shape-id-1" "shape-id-2" "shape-id-3")}}
:block/type "whiteboard"
:block/name "whiteboard-name"
:block/original-name "Whiteboard Name"
:block/created-at 1728698317371
:block/updated-at 1728698317371}
)}
Shape Types
LogSeq whiteboards support 8 shape types:
| Type | Description |
|---|---|
"text" |
Text labels and paragraphs |
"box" |
Rectangles with optional labels |
"line" |
Lines and arrows (connectors) |
"pencil" |
Freehand drawings |
"image" |
Images (references assets) |
"logseq-portal" |
Embedded LogSeq pages or blocks |
"youtube" |
Embedded YouTube videos |
"iframe" |
Embedded web pages |
Common Shape Properties
All shapes share these properties within :logseq.tldraw.shape:
| Property | Type | Description |
|---|---|---|
:type |
String | Shape type (see table above) |
:id |
String | Unique UUID for this shape |
:point |
[x y] |
Position (top-left corner) on canvas |
:size |
[width height] |
Dimensions in pixels |
:index |
Integer | Z-order (rendering layer, higher = on top) |
:scale |
[sx sy] |
Scale factors (usually [1 1]) |
:opacity |
Number | Opacity 0.0 to 1.0 |
:rotation |
Number | Rotation in radians (0 = no rotation) |
:parentId |
String | Parent shape ID (page ID for top-level shapes) |
:nonce |
Integer | Timestamp for change tracking |
Text Shape
Text labels and headings on the canvas.
{:logseq.tldraw.shape
{:type "text"
:id "uuid-here"
:point [100 200]
:size [300 50]
:text "Hello World"
:fontSize 32 ;; Font size in pixels
:fontFamily "'Inter'" ;; Font family (CSS)
:fontWeight 700 ;; 400 = normal, 700 = bold
:italic false ;; Italic text
:lineHeight 1.2 ;; Line height multiplier
:isSizeLocked true ;; Size auto-adjusts to text
:scaleLevel "lg" ;; "xs", "sm", "md", "lg", "xl"
:padding 4 ;; Internal padding
:stroke "var(--tl-foreground, #000)"
:fill "#ffffff"
:noFill true ;; true = transparent background
:strokeType "line"
:strokeWidth 2
:borderRadius 0
:index 0
:scale [1 1]
:opacity 1
:parentId "page-uuid"
:nonce 1664366266517}}
Scale levels control default font sizes:
| Level | Typical fontSize |
|---|---|
"xs" |
12 |
"sm" |
16 |
"md" |
20 |
"lg" |
32 |
"xl" |
48 |
Box Shape
Rectangles for containers, cards, and labeled shapes.
{:logseq.tldraw.shape
{:type "box"
:id "uuid-here"
:point [0 0]
:size [1071 578]
:label "" ;; Text label inside box (can be empty)
:stroke "#ababab" ;; Border color
:fill "var(--ls-secondary-background-color)" ;; Fill color
:noFill false ;; false = filled, true = transparent
:strokeType "line" ;; "line" or "dashed"
:strokeWidth 2
:borderRadius 2 ;; Corner rounding in pixels
:fontSize 20 ;; Label font size
:fontWeight 400
:italic false
:rotation 0
:index 1
:scale [1 1]
:opacity 1
:parentId "page-uuid"
:nonce 1664366266231}}
Line Shape (Connectors and Arrows)
Lines connect shapes with optional arrowheads and labels.
{:logseq.tldraw.shape
{:type "line"
:id "uuid-here"
:point [2824 284] ;; Base point (origin for handles)
:stroke "var(--ls-primary-text-color, #000)"
:fill "var(--ls-secondary-background-color)"
:noFill true
:strokeType "line" ;; "line" or "dashed"
:strokeWidth 1
:label "" ;; Text label on the line
:fontSize 20
:fontWeight 400
:italic false
:handles ;; Start and end points (relative to :point)
{:start
{:id "start"
:canBind true ;; Can snap to other shapes
:point [0 0] ;; Relative position [x y]
:bindingId nil} ;; UUID of bound shape (nil = unbound)
:end
{:id "end"
:canBind true
:point [52 0] ;; End point relative to base
:bindingId nil}}
:decorations ;; Arrowheads
{:start nil ;; nil or "arrow"
:end "arrow"} ;; nil or "arrow"
:index 28
:scale [1 1]
:opacity 1
:parentId "page-uuid"
:nonce 1664464964296}}
Decorations: Set :start and/or :end to "arrow" for arrowheads. Use nil for no arrowhead.
Bindings: When a line connects to a shape, :bindingId references the bound shape's ID. The :bindings map in the page metadata tracks these connections.
Pencil Shape (Freehand Drawing)
Freehand strokes from the pencil tool.
{:logseq.tldraw.shape
{:type "pencil"
:id "uuid-here"
:point [212 160] ;; Base position
:points [[0 0 0.5]] ;; Array of [x y pressure] points (relative)
:stroke "" ;; Stroke color (empty = theme default)
:fill ""
:noFill true
:strokeType "line"
:strokeWidth 2
:scaleLevel "md"
:isComplete true ;; true when stroke is finished
:index 0
:scale [1 1]
:opacity 1
:parentId "page-uuid"
:nonce 1730788259525}}
Each point in :points is [x y pressure] where:
x,yare relative to the shape's:pointpressureis pen pressure (0.0 to 1.0, typically 0.5 for mouse)
Image Shape
Images reference assets stored in the graph's assets/ directory.
{:logseq.tldraw.shape
{:type "image"
:id "uuid-here"
:point [136 200]
:size [260 105]
:assetId "asset-uuid" ;; References asset in page's :assets array
:isAspectRatioLocked true ;; Preserve aspect ratio on resize
:isLocked false ;; Prevent accidental moves
:objectFit "fill" ;; "fill", "contain", "cover"
:clipping 0 ;; Clipping amount
:index 0
:scale [1 1]
:opacity 1
:parentId "page-uuid"
:nonce 1770432010158}}
Assets are defined in the page's :assets array:
:assets [
{:id "asset-uuid"
:type "image"
:src "../assets/image_1770432010069_0.png" ;; Relative path
:size [520 210]}] ;; Original dimensions
LogSeq Portal Shape
The unique LogSeq feature — embed pages or blocks from your graph directly onto the whiteboard.
{:logseq.tldraw.shape
{:type "logseq-portal"
:id "uuid-here"
:point [256 168]
:size [400 141]
:blockType "P" ;; "P" = page portal, "B" = block portal
:pageId "PageName" ;; Page name (for page portals)
;; :blockId "block-uuid" ;; Block UUID (for block portals)
:collapsed false ;; true = show only title
:collapsedHeight 0 ;; Height when collapsed
:compact false ;; Compact display mode
:isAutoResizing true ;; Auto-resize to fit content
:stroke ""
:fill ""
:noFill false
:strokeType "line"
:strokeWidth 2
:borderRadius 8
:scaleLevel "md"
:index 2
:scale [1 1]
:opacity 1
:parentId "page-uuid"
:nonce 1731296148685}}
Portal types:
- Page portal (
blockType: "P"): Uses:pageId— embeds an entire page - Block portal (
blockType: "B"): Uses:blockId— embeds a single block and its children
Portals render live LogSeq content. Editing the portal edits the actual page/block.
YouTube Shape
Embed YouTube videos on the canvas.
{:logseq.tldraw.shape
{:type "youtube"
:id "uuid-here"
:point [7383 321]
:size [283 159]
:url "https://www.youtube.com/watch?v=VIDEO_ID"
:rotation 0
:index 49
:scale [1 1]
:parentId "page-uuid"
:nonce 1664531347941}}
IFrame Shape
Embed any web page on the canvas.
{:logseq.tldraw.shape
{:type "iframe"
:id "uuid-here"
:point [7730 321]
:size [282 158]
:url "https://logseq.com/"
:rotation 0
:index 50
:scale [1 1]
:parentId "page-uuid"
:nonce 1664531425980}}
Page Metadata
The :pages section contains canvas-level metadata:
{:block/uuid #uuid "page-uuid"
:block/properties
{:ls-type :whiteboard-page
:logseq.tldraw.page
{:id "page-uuid"
:name "whiteboard-name" ;; Lowercase page name
:bindings {} ;; Shape-to-shape binding map
:nonce 1 ;; Change counter
:assets [ ;; Image assets used by shapes
{:id "asset-uuid"
:type "image"
:src "../assets/filename.png"
:size [width height]}]
:shapes-index ("id1" "id2")}} ;; Ordered list of shape IDs
:block/type "whiteboard"
:block/name "whiteboard-name" ;; Lowercase
:block/original-name "Whiteboard Name" ;; Original case
:block/created-at 1728698317371
:block/updated-at 1728698317371}
:shapes-index controls the order shapes are listed. This is a list of shape IDs.
:bindings tracks connections between lines and shapes when :bindingId is set on line handles.
:assets stores metadata for images used by image shapes. The :src path is relative to the graph root.
Color Values
Shapes support these color formats:
| Format | Example |
|---|---|
| Hex color | "#ababab", "#ffffff" |
| CSS variable | "var(--ls-primary-text-color, #000)" |
| Named color | "gray" |
| Empty (theme default) | "" |
Common CSS variables:
var(--ls-primary-text-color, #000)— primary textvar(--ls-secondary-background-color)— secondary backgroundvar(--tl-foreground, #000)— tldraw foreground
Coordinate System
- Origin: Top-left of the canvas (can extend into negative coordinates)
- X axis: Increases to the right
- Y axis: Increases downward
:pointis the top-left corner of each shape:sizeis[width height]in pixels:handleson lines are relative to the line's:point
Complete Example
A minimal whiteboard with a box, text label, and an arrow:
{:blocks (
{:block/created-at 1700000000000
:block/properties
{:ls-type :whiteboard-shape
:logseq.tldraw.shape
{:type "box"
:id "box-1"
:point [100 100]
:size [200 100]
:stroke "#ababab"
:fill "var(--ls-secondary-background-color)"
:noFill false
:strokeType "line"
:strokeWidth 2
:borderRadius 8
:label "My Box"
:fontSize 20
:fontWeight 400
:italic false
:rotation 0
:index 0
:scale [1 1]
:opacity 1
:parentId "page-1"
:nonce 1700000000000}}
:block/updated-at 1700000000000}
{:block/created-at 1700000000001
:block/properties
{:ls-type :whiteboard-shape
:logseq.tldraw.shape
{:type "text"
:id "text-1"
:point [100 50]
:size [200 30]
:text "Hello Canvas"
:fontSize 24
:fontFamily "'Inter'"
:fontWeight 700
:italic false
:lineHeight 1.2
:isSizeLocked true
:scaleLevel "lg"
:padding 4
:stroke ""
:fill ""
:noFill true
:strokeType "line"
:strokeWidth 2
:borderRadius 0
:index 1
:scale [1 1]
:opacity 1
:parentId "page-1"
:nonce 1700000000001}}
:block/updated-at 1700000000001}
{:block/created-at 1700000000002
:block/properties
{:ls-type :whiteboard-shape
:logseq.tldraw.shape
{:type "line"
:id "arrow-1"
:point [350 150]
:stroke ""
:fill ""
:noFill true
:strokeType "line"
:strokeWidth 1
:label ""
:fontSize 20
:fontWeight 400
:italic false
:handles
{:start
{:id "start"
:canBind true
:point [0 0]
:bindingId nil}
:end
{:id "end"
:canBind true
:point [100 0]
:bindingId nil}}
:decorations
{:end "arrow"}
:index 2
:scale [1 1]
:opacity 1
:parentId "page-1"
:nonce 1700000000002}}
:block/updated-at 1700000000002})
:pages (
{:block/uuid #uuid "00000000-0000-0000-0000-000000000001"
:block/properties
{:ls-type :whiteboard-page
:logseq.tldraw.page
{:id "page-1"
:name "my-diagram"
:bindings {}
:nonce 1
:assets []
:shapes-index ("box-1" "text-1" "arrow-1")}}
:block/type "whiteboard"
:block/name "my-diagram"
:block/original-name "My Diagram"
:block/created-at 1700000000000
:block/updated-at 1700000000002})}
Tips
- EDN format — Uses Clojure-style syntax:
{}for maps,()for lists,[]for vectors,:keywordfor keys - UUIDs — Shape IDs are typically UUID v1 format (time-based), page UUIDs use
#uuid "..."reader literal - parentId — Top-level shapes set
:parentIdto the page's UUID string - Assets — Images must have both an entry in
:assets(page level) and a shape with matching:assetId - Portals are live — LogSeq portal shapes render actual graph content; edits sync bidirectionally
- CSS variables — Use LogSeq CSS variables for theme-aware colors
- Whiteboard = page — Every whiteboard is also a LogSeq page with
:block/type "whiteboard"
References
- LogSeq Whiteboards Announcement
- tldraw SDK (base canvas library)
- LogSeq GitHub
- EDN Format Specification