Files
upstream-affine/blocksuite/docs-site/components/editors/edgeless-data-structure.md
upstream-mirror 702cc698a7
Some checks failed
Build & Test / Analyze (javascript, affine) (push) Failing after 4s
Build & Test / Analyze (typescript, affine) (push) Failing after 3s
Build & Test / Rust test filter (push) Failing after 4s
Build & Test / Check yarn binary (push) Failing after 3s
Build & Test / E2E BlockSuite Test (3) (push) Failing after 3s
Build & Test / Analyze (javascript, blocksuite) (push) Failing after 3s
Build & Test / Analyze (typescript, blocksuite) (push) Failing after 3s
Build & Test / Mobile native build filter (push) Failing after 3s
Build & Test / E2E BlockSuite Test (1) (push) Failing after 4s
Build & Test / E2E BlockSuite Test (2) (push) Failing after 4s
Build & Test / E2E Mobile Test (1) (push) Failing after 3s
Build & Test / Unit Test (1) (push) Has been skipped
Build & Test / Unit Test (2) (push) Has been skipped
Build & Test / Unit Test (3) (push) Has been skipped
Build & Test / Unit Test (4) (push) Has been skipped
Build & Test / Unit Test (5) (push) Has been skipped
Build & Test / Native Unit Test (push) Has been skipped
Build & Test / E2E BlockSuite Test (4) (push) Failing after 3s
Build & Test / E2E BlockSuite Test (5) (push) Failing after 3s
Build & Test / E2E BlockSuite Cross Browser Test (push) Failing after 3s
Build & Test / E2E Mobile Test (2) (push) Failing after 3s
Build & Test / Build AFFiNE native (x86_64-unknown-linux-gnu) (push) Failing after 3s
Build & Test / Build Server native (push) Failing after 3s
Build & Test / Check Git Status (push) Has been skipped
Build & Test / Server Test (0, 4) (push) Has been skipped
Build & Test / Server Test (1, 4) (push) Has been skipped
Build & Test / Server Test (2, 4) (push) Has been skipped
Build & Test / Server Test (3, 4) (push) Has been skipped
Build & Test / Server Test with Elasticsearch (push) Has been skipped
Build & Test / Build @affine/electron renderer (push) Failing after 3s
Build & Test / Copilot test filter (push) Failing after 4s
Build & Test / Lint Rust (push) Has been skipped
Build & Test / Server Test with Embedded Search (push) Has been skipped
Build & Test / Server Test with Manticore Search (push) Has been skipped
Build & Test / Server E2E Test (push) Has been skipped
Build & Test / Cloud Desktop E2E Test (push) Has been skipped
Build & Test / Cloud E2E Test 1/2 (push) Has been skipped
Build & Test / Cloud E2E Test 2/2 (push) Has been skipped
Build & Test / Build Android app (push) Has been skipped
Build & Test / Test Android app (push) Has been skipped
Build & Test / Run native tests (push) Has been skipped
Build & Test / Server Copilot Api Test (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (1, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (2, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (3, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (4, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (5, 5) (push) Has been skipped
Release / Canary Gate (push) Has been skipped
Build & Test / Build AFFiNE native (aarch64-apple-darwin) (push) Has been cancelled
Build & Test / Lint (push) Has been cancelled
Build & Test / Typecheck (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-apple-darwin) (push) Has been cancelled
Build & Test / Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true) (push) Has been cancelled
Build & Test / Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true) (push) Has been cancelled
Build & Test / E2E Test (1) (push) Has been cancelled
Build & Test / E2E Test (2) (push) Has been cancelled
Build & Test / E2E Test (3) (push) Has been cancelled
Build & Test / E2E Test (4) (push) Has been cancelled
Build & Test / E2E Test (5) (push) Has been cancelled
Build & Test / Build AFFiNE native (aarch64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, x64, x86_64-apple-darwin, false) (push) Has been cancelled
Build & Test / 3, 2, 1 Launch (push) Has been cancelled
Build & Test / Build iOS app (push) Has been cancelled
Copilot Test Automatically / Setup Test (push) Failing after 1s
Release / Prepare (push) Failing after 2s
Release / Release Cloud (push) Has been skipped
Release / Release Desktop (push) Has been skipped
Release / Release Docker Image (push) Has been skipped
Release / Release Mobile (push) Has been skipped
snapshot of https://github.com/toeverything/AFFiNE.git (canary, 2026-09-16; blobs > 131072B omitted)
2026-09-16 04:01:20 +05:00

5.0 KiB

Edgeless Data Structure

Fundamentals

In BlockSuite, documents in edgeless mode are isomorphic to those in page mode. Edgeless documents are also composed of blocks, with no data conversion occurring during mode switching.

By default, the root block of a rich text document contains a single note block child, with a block tree structure like this:

Root Block
  Note Block
    Paragraph Block 1
    Paragraph Block 2
    Paragraph Block 3

In the edgeless editor, you can easily split the document into multiple note cards, which can be positioned separately on the edgeless canvas, resulting in this block tree structure:

Root Block
  Note Block
    Paragraph Block 1
  Note Block
    Paragraph Block 2
    Paragraph Block 3

Surface Block and Surface Element

Edgeless mode introduces additional editable content such as brushes, connectors, and geometric shapes. To accommodate this, the edgeless editor implements a surface block as a container for whiteboard graphical content. Documents compatible with both edgeless and page modes have a default surface block as the first child of the root block:

Root Block
  Surface Block
  Note Block
    Paragraph Block 1
  Note Block
    Paragraph Block 2
    Paragraph Block 3

The surface block can store two types of content:

  • The block.children field can contain edgeless-specific card blocks, such as embed-style links to YouTube, Figma, or other BlockSuite documents.
  • Graphical content like brushstrokes and polygons are modeled as SurfaceElements and stored in the block.elements field. Common element types include BrushElement, ShapeElement, and ConnectorElement.

A typical edgeless document structure with a surface block might look like this:

Root Block
  Surface Block
    Embed Block
    Shape Element
    Brush Element
  Note Block
    Paragraph Block 1
  Note Block
    Paragraph Block 2
    Paragraph Block 3

Surface Block as Parent Block

With the introduction of the surface block, blocks can have two potential storage locations:

  • Blocks used exclusively in the edgeless editor without nesting can be stored as direct children of the surface block.
  • Other blocks are stored outside the surface block, as in rich text mode. These blocks can be reused between rich text and edgeless editor modes and allow complex nesting structures.

BlockSuite allows specific block types to appear in both locations. For example:

Root Block
  Surface Block
    Image Block 1
  Note Block
    Image Block 2
    Image Block 3

In the example above, the image blocks appear under both the note block and the surface block. The edgeless editor can display all three image blocks simultaneously. The key difference is that the image with the surface block as its parent can be placed anywhere on the whiteboard, while the images within the note block must be arranged from top to bottom according to the note's internal layout.

Block and Element Hierarchy

Although the block tree shows node adjacency, this relationship doesn't determine the content hierarchy in the whiteboard, which needs to render both blocks and surface elements.

Instead, BlockSuite allows specific block types to determine hierarchy order along with surface elements, including:

  • Note blocks
  • All children of the surface block

Blocks with adjustable hierarchy dynamically receive an index field. Since all surface elements also have this field, comparing the index values of these indexable blocks and elements uniquely determines the edgeless content hierarchy.

In this example:

Root Block
  Surface Block
    Brush Element
    Image Block 1
  Note Block
    Paragraph Block 1
    Paragraph Block 2
    Image Block 2

The note block and image block 1 have index fields and can adjust their hierarchy order along with the brush element. The paragraph blocks and image block 2 within the note block are rendered as children of the note block and don't intersect with surface elements hierarchically.

All indexable blocks and surface elements have an xywh field, determining their absolute position on the edgeless canvas.

This hierarchy determination technique is called fractional indexing, also used by Figma.

Frames and Groups

There are two ways to associate blocks and/or elements in the edgeless editor: frames and groups.

  • Frame blocks are surface-only blocks with specific xywh dimensions. Dragging a frame moves all blocks and elements within its xywh area, establishing a dynamic association based on geometric region. Multiple frames can overlap positionally but cannot nest in the block tree.
  • Group elements are special surface elements without inherent dimensions, determined by their children. Groups store the IDs of all child nodes. All indexable blocks and elements can be group children, and groups can nest multiple levels.

Developers can extend these association mechanisms to create more dynamic nesting relationships, implementing element types like MindmapElement with more dynamic linking effects.